apex-ruby 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +119 -0
- data/apex-ruby.gemspec +31 -0
- data/ext/apex_ext/apex_ext.c +215 -0
- data/ext/apex_ext/apex_src/BENCHMARK.md +32 -0
- data/ext/apex_ext/apex_src/BENCHMARK_COMPARISON.md +67 -0
- data/ext/apex_ext/apex_src/CHANGELOG.md +2454 -0
- data/ext/apex_ext/apex_src/CMakeLists.txt +454 -0
- data/ext/apex_ext/apex_src/Dockerfile.linux-build +15 -0
- data/ext/apex_ext/apex_src/Formula/apex.rb +38 -0
- data/ext/apex_ext/apex_src/Info.plist.in +27 -0
- data/ext/apex_ext/apex_src/LICENSE +21 -0
- data/ext/apex_ext/apex_src/Package.swift +160 -0
- data/ext/apex_ext/apex_src/PackageSupport/README.md +17 -0
- data/ext/apex_ext/apex_src/PackageSupport/cmark-gfm/cmark-gfm_export.h +20 -0
- data/ext/apex_ext/apex_src/PackageSupport/cmark-gfm/cmark-gfm_version.h +14 -0
- data/ext/apex_ext/apex_src/PackageSupport/cmark-gfm/cmark_gfm_spm_stub.c +4 -0
- data/ext/apex_ext/apex_src/PackageSupport/cmark-gfm/config.h +41 -0
- data/ext/apex_ext/apex_src/README.md +452 -0
- data/ext/apex_ext/apex_src/VERSION +1 -0
- data/ext/apex_ext/apex_src/apex-header-2-rb@2x.webp +0 -0
- data/ext/apex_ext/apex_src/apex-plugins.json.example +20 -0
- data/ext/apex_ext/apex_src/apex.pc.in +11 -0
- data/ext/apex_ext/apex_src/cli/main.c +2720 -0
- data/ext/apex_ext/apex_src/debug_test.sh +22 -0
- data/ext/apex_ext/apex_src/docs/API_REFERENCE.md +451 -0
- data/ext/apex_ext/apex_src/docs/ARCHITECTURE.md +166 -0
- data/ext/apex_ext/apex_src/docs/CMARK_INTEGRATION.md +220 -0
- data/ext/apex_ext/apex_src/docs/CRITICMARKUP.md +501 -0
- data/ext/apex_ext/apex_src/docs/DEBUGGING.md +73 -0
- data/ext/apex_ext/apex_src/docs/FINAL_STATUS.md +391 -0
- data/ext/apex_ext/apex_src/docs/FINAL_STATUS_UPDATE.md +237 -0
- data/ext/apex_ext/apex_src/docs/FUTURE_FEATURES.md +456 -0
- data/ext/apex_ext/apex_src/docs/IAL_FEATURES.md +210 -0
- data/ext/apex_ext/apex_src/docs/IAL_STATUS.md +344 -0
- data/ext/apex_ext/apex_src/docs/INTEGRATION_EXAMPLE.m +144 -0
- data/ext/apex_ext/apex_src/docs/LIMITATIONS_RESOLVED.md +278 -0
- data/ext/apex_ext/apex_src/docs/OUTPUT_MODES.md +321 -0
- data/ext/apex_ext/apex_src/docs/PROGRESS.md +167 -0
- data/ext/apex_ext/apex_src/docs/STANDALONE_FEATURE.md +174 -0
- data/ext/apex_ext/apex_src/docs/TABLE_SPANS_STATUS.md +243 -0
- data/ext/apex_ext/apex_src/docs/TEST_COVERAGE.md +316 -0
- data/ext/apex_ext/apex_src/docs/USER_GUIDE.md +803 -0
- data/ext/apex_ext/apex_src/docs/WIKI_LINKS_ISSUE.md +91 -0
- data/ext/apex_ext/apex_src/documentation/README.md +160 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex Command Line Options.cheatsheet.txt +365 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Info.plist +24 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/C-API.html +1737 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Citations.html +1420 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Command-Line-Options.html +3574 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Configuration.html +1603 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Credits.html +910 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Examples.html +1168 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Getting-Started.html +1003 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Header-IDs.html +1308 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Home.html +1078 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Inline-Attribute-Lists.html +1622 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Installation.html +1168 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Limitations-and-Roadmap.html +1698 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Metadata-Transforms.html +1531 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Modes.html +1980 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Multi-File-Documents.html +1368 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Pandoc-Integration.html +1151 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Plugins.html +2861 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Syntax.html +3981 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Troubleshooting.html +1454 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Usage.html +1200 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/Documents/Xcode-Integration.html +2066 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/docSet.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/Apex.docset/Contents/Resources/tempOptimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Info.plist +22 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Bold.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Bold_Italic.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Extrabold.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Extrabold_Italic.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Italic.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Semibold.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/cheatset_resources/Open_Sans_Semibold_Italic.woff +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/index.html +914 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/Documents/style.css +399 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/docSet.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/docsets/ApexCLI.docset/Contents/Resources/optimizedIndex.dsidx +0 -0
- data/ext/apex_ext/apex_src/documentation/generate_app_docs.rb +772 -0
- data/ext/apex_ext/apex_src/documentation/generate_app_docs_ai.rb +678 -0
- data/ext/apex_ext/apex_src/documentation/generate_docset.rb +873 -0
- data/ext/apex_ext/apex_src/documentation/generate_single_html.rb +733 -0
- data/ext/apex_ext/apex_src/documentation/html/apex-docs.html +17073 -0
- data/ext/apex_ext/apex_src/documentation/shared_scripts.js +64 -0
- data/ext/apex_ext/apex_src/documentation/shared_styles.css +646 -0
- data/ext/apex_ext/apex_src/documentation/transform_for_app.example.md +260 -0
- data/ext/apex_ext/apex_src/examples/bracketed_spans_demo.md +119 -0
- data/ext/apex_ext/apex_src/examples/emoji_span_plugin.yml +11 -0
- data/ext/apex_ext/apex_src/examples/example.html +53 -0
- data/ext/apex_ext/apex_src/examples/example.md +85 -0
- data/ext/apex_ext/apex_src/examples/fenced_divs_demo.md +158 -0
- data/ext/apex_ext/apex_src/examples/kbd.md +8 -0
- data/ext/apex_ext/apex_src/examples/kbd_plugin.rb +250 -0
- data/ext/apex_ext/apex_src/examples/kbd_plugin.yml +9 -0
- data/ext/apex_ext/apex_src/icon/apexicon-outline-black.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon-outline-black@2x.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon-outline-mark.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon-outline-mark@2x.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon-outline-white.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon-outline-white@2x.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon.png +0 -0
- data/ext/apex_ext/apex_src/icon/apexicon@2x.png +0 -0
- data/ext/apex_ext/apex_src/include/apex/apex.h +247 -0
- data/ext/apex_ext/apex_src/include/apex/buffer.h +93 -0
- data/ext/apex_ext/apex_src/include/apex/module.modulemap +16 -0
- data/ext/apex_ext/apex_src/include/apex/parser.h +150 -0
- data/ext/apex_ext/apex_src/include/apex/renderer.h +39 -0
- data/ext/apex_ext/apex_src/man/apex-config.5 +374 -0
- data/ext/apex_ext/apex_src/man/apex-config.5.md +260 -0
- data/ext/apex_ext/apex_src/man/apex-plugins.7 +456 -0
- data/ext/apex_ext/apex_src/man/apex-plugins.7.md +365 -0
- data/ext/apex_ext/apex_src/man/apex.1 +828 -0
- data/ext/apex_ext/apex_src/man/apex.1.md +643 -0
- data/ext/apex_ext/apex_src/man/apex.1.new +338 -0
- data/ext/apex_ext/apex_src/objc/Apex.swift +237 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.h +117 -0
- data/ext/apex_ext/apex_src/objc/NSString+Apex.m +332 -0
- data/ext/apex_ext/apex_src/src/_README.md +358 -0
- data/ext/apex_ext/apex_src/src/apex.c +6326 -0
- data/ext/apex_ext/apex_src/src/buffer.c +93 -0
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.c +362 -0
- data/ext/apex_ext/apex_src/src/extensions/abbreviations.h +45 -0
- data/ext/apex_ext/apex_src/src/extensions/advanced_footnotes.c +184 -0
- data/ext/apex_ext/apex_src/src/extensions/advanced_footnotes.h +50 -0
- data/ext/apex_ext/apex_src/src/extensions/advanced_tables.c +1897 -0
- data/ext/apex_ext/apex_src/src/extensions/advanced_tables.h +42 -0
- data/ext/apex_ext/apex_src/src/extensions/callouts.c +215 -0
- data/ext/apex_ext/apex_src/src/extensions/callouts.h +53 -0
- data/ext/apex_ext/apex_src/src/extensions/citations.c +2042 -0
- data/ext/apex_ext/apex_src/src/extensions/citations.h +163 -0
- data/ext/apex_ext/apex_src/src/extensions/critic.c +329 -0
- data/ext/apex_ext/apex_src/src/extensions/critic.h +48 -0
- data/ext/apex_ext/apex_src/src/extensions/definition_list.c +1670 -0
- data/ext/apex_ext/apex_src/src/extensions/definition_list.h +42 -0
- data/ext/apex_ext/apex_src/src/extensions/emoji.c +710 -0
- data/ext/apex_ext/apex_src/src/extensions/emoji.h +38 -0
- data/ext/apex_ext/apex_src/src/extensions/emoji_data.h +942 -0
- data/ext/apex_ext/apex_src/src/extensions/fenced_divs.c +925 -0
- data/ext/apex_ext/apex_src/src/extensions/fenced_divs.h +43 -0
- data/ext/apex_ext/apex_src/src/extensions/github-emoji.txt +869 -0
- data/ext/apex_ext/apex_src/src/extensions/grid_tables.c +1121 -0
- data/ext/apex_ext/apex_src/src/extensions/grid_tables.h +33 -0
- data/ext/apex_ext/apex_src/src/extensions/header_ids.c +626 -0
- data/ext/apex_ext/apex_src/src/extensions/header_ids.h +60 -0
- data/ext/apex_ext/apex_src/src/extensions/highlight.c +135 -0
- data/ext/apex_ext/apex_src/src/extensions/highlight.h +16 -0
- data/ext/apex_ext/apex_src/src/extensions/html_markdown.c +408 -0
- data/ext/apex_ext/apex_src/src/extensions/html_markdown.h +42 -0
- data/ext/apex_ext/apex_src/src/extensions/ial.c +4084 -0
- data/ext/apex_ext/apex_src/src/extensions/ial.h +145 -0
- data/ext/apex_ext/apex_src/src/extensions/includes.c +1536 -0
- data/ext/apex_ext/apex_src/src/extensions/includes.h +54 -0
- data/ext/apex_ext/apex_src/src/extensions/index.c +967 -0
- data/ext/apex_ext/apex_src/src/extensions/index.h +90 -0
- data/ext/apex_ext/apex_src/src/extensions/inline_footnotes.c +205 -0
- data/ext/apex_ext/apex_src/src/extensions/inline_footnotes.h +34 -0
- data/ext/apex_ext/apex_src/src/extensions/inline_tables.c +332 -0
- data/ext/apex_ext/apex_src/src/extensions/inline_tables.h +13 -0
- data/ext/apex_ext/apex_src/src/extensions/insert.c +248 -0
- data/ext/apex_ext/apex_src/src/extensions/insert.h +18 -0
- data/ext/apex_ext/apex_src/src/extensions/math.c +279 -0
- data/ext/apex_ext/apex_src/src/extensions/math.h +32 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.c +3046 -0
- data/ext/apex_ext/apex_src/src/extensions/metadata.h +125 -0
- data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.c +1297 -0
- data/ext/apex_ext/apex_src/src/extensions/relaxed_tables.h +39 -0
- data/ext/apex_ext/apex_src/src/extensions/special_markers.c +194 -0
- data/ext/apex_ext/apex_src/src/extensions/special_markers.h +29 -0
- data/ext/apex_ext/apex_src/src/extensions/sup_sub.c +405 -0
- data/ext/apex_ext/apex_src/src/extensions/sup_sub.h +16 -0
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.c +468 -0
- data/ext/apex_ext/apex_src/src/extensions/syntax_highlight.h +44 -0
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.c +2679 -0
- data/ext/apex_ext/apex_src/src/extensions/table_html_postprocess.h +23 -0
- data/ext/apex_ext/apex_src/src/extensions/toc.c +255 -0
- data/ext/apex_ext/apex_src/src/extensions/toc.h +34 -0
- data/ext/apex_ext/apex_src/src/extensions/wiki_links.c +624 -0
- data/ext/apex_ext/apex_src/src/extensions/wiki_links.h +58 -0
- data/ext/apex_ext/apex_src/src/html_renderer.c +2762 -0
- data/ext/apex_ext/apex_src/src/html_renderer.h +126 -0
- data/ext/apex_ext/apex_src/src/parser.c +227 -0
- data/ext/apex_ext/apex_src/src/plugins.c +895 -0
- data/ext/apex_ext/apex_src/src/plugins.h +39 -0
- data/ext/apex_ext/apex_src/src/plugins_env.c +187 -0
- data/ext/apex_ext/apex_src/src/plugins_remote.c +263 -0
- data/ext/apex_ext/apex_src/src/pretty_html.c +358 -0
- data/ext/apex_ext/apex_src/src/renderer.c +241 -0
- data/ext/apex_ext/apex_src/src/utf8.c +56 -0
- data/ext/apex_ext/apex_src/test-linux-build.sh +20 -0
- data/ext/apex_ext/apex_src/test.html +103 -0
- data/ext/apex_ext/apex_src/test_coverage.sh +121 -0
- data/ext/apex_ext/apex_src/test_ial_fenced.md +6 -0
- data/ext/apex_ext/apex_src/test_math_norm.py +79 -0
- data/ext/apex_ext/apex_src/test_pandoc_output.html +48 -0
- data/ext/apex_ext/apex_src/test_spm.sh +107 -0
- data/ext/apex_ext/apex_src/tests/ApexSPMTest/main.swift +50 -0
- data/ext/apex_ext/apex_src/tests/BENCHMARK_RESULTS.md +229 -0
- data/ext/apex_ext/apex_src/tests/CMakeLists.txt +24 -0
- data/ext/apex_ext/apex_src/tests/README.md +146 -0
- data/ext/apex_ext/apex_src/tests/benchmark.sh +113 -0
- data/ext/apex_ext/apex_src/tests/benchmark_comparison.sh +166 -0
- data/ext/apex_ext/apex_src/tests/compare_header_ids.sh +31 -0
- data/ext/apex_ext/apex_src/tests/fixtures/basic/headers.md +25 -0
- data/ext/apex_ext/apex_src/tests/fixtures/basic/list-interruption.md +24 -0
- data/ext/apex_ext/apex_src/tests/fixtures/basic/misc_markup.md +33 -0
- data/ext/apex_ext/apex_src/tests/fixtures/basic/test_basic.md +26 -0
- data/ext/apex_ext/apex_src/tests/fixtures/code/code-blocks.md +260 -0
- data/ext/apex_ext/apex_src/tests/fixtures/combine_summary/SUMMARY.md +6 -0
- data/ext/apex_ext/apex_src/tests/fixtures/combine_summary/chapter1.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/combine_summary/index.txt +9 -0
- data/ext/apex_ext/apex_src/tests/fixtures/combine_summary/intro.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/combine_summary/section1_1.md +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/comprehensive_test.md +620 -0
- data/ext/apex_ext/apex_src/tests/fixtures/debug_ref_image_ial.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/demos/ial.md +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/demos/ial_demo.md +177 -0
- data/ext/apex_ext/apex_src/tests/fixtures/extensions/emoji-autocorrect.md +94 -0
- data/ext/apex_ext/apex_src/tests/fixtures/extensions/emoji_test.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/extensions/kbd_test.md +3 -0
- data/ext/apex_ext/apex_src/tests/fixtures/ial/bracketed_spans_test.md +74 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/image_and_encoding_test.md +27 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/multimarkdown_image_attributes_test.md +60 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/pandoc_ial_image_test.md +27 -0
- data/ext/apex_ext/apex_src/tests/fixtures/images/width_height_conversion_test.md +94 -0
- data/ext/apex_ext/apex_src/tests/fixtures/img-in-div.md +16 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/code.py +4 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/data.csv +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/data.tsv +5 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/image.png +2 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/metadata_options.yml +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/nested.md +8 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/raw.html +4 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/simple.md +7 -0
- data/ext/apex_ext/apex_src/tests/fixtures/includes/test_image.png +0 -0
- data/ext/apex_ext/apex_src/tests/fixtures/large_doc.md +1094 -0
- data/ext/apex_ext/apex_src/tests/fixtures/metadata_options.yml +11 -0
- data/ext/apex_ext/apex_src/tests/fixtures/output/gfm_header_id_test.md +96 -0
- data/ext/apex_ext/apex_src/tests/fixtures/output/test_citations.md +43 -0
- data/ext/apex_ext/apex_src/tests/fixtures/output/test_def_list_links.md +12 -0
- data/ext/apex_ext/apex_src/tests/fixtures/output/test_index_mmark.md +53 -0
- data/ext/apex_ext/apex_src/tests/fixtures/output/test_index_textindex.md +37 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/advanced_tables_test.md +93 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/inline_tables_test.md +38 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/relaxed-table.md +12 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/table_cr_line_endings.md +15 -0
- data/ext/apex_ext/apex_src/tests/fixtures/tables/table_no_trailing_newline.md +15 -0
- data/ext/apex_ext/apex_src/tests/generate_gfm_ids.sh +105 -0
- data/ext/apex_ext/apex_src/tests/generate_ial_demo.sh +143 -0
- data/ext/apex_ext/apex_src/tests/gfm_id_comparison_summary.md +96 -0
- data/ext/apex_ext/apex_src/tests/gh_api_test.md +6 -0
- data/ext/apex_ext/apex_src/tests/ial_demo.html +186 -0
- data/ext/apex_ext/apex_src/tests/include_code.py +19 -0
- data/ext/apex_ext/apex_src/tests/include_snippet.md +15 -0
- data/ext/apex_ext/apex_src/tests/multi_file_cli_test.sh +64 -0
- data/ext/apex_ext/apex_src/tests/sample_data.csv +7 -0
- data/ext/apex_ext/apex_src/tests/table_escaped_ltlt.md +4 -0
- data/ext/apex_ext/apex_src/tests/test_basic.c +74 -0
- data/ext/apex_ext/apex_src/tests/test_extensions.c +2116 -0
- data/ext/apex_ext/apex_src/tests/test_helpers.c +183 -0
- data/ext/apex_ext/apex_src/tests/test_helpers.h +91 -0
- data/ext/apex_ext/apex_src/tests/test_ial.c +282 -0
- data/ext/apex_ext/apex_src/tests/test_links.c +418 -0
- data/ext/apex_ext/apex_src/tests/test_marked_integration.c +265 -0
- data/ext/apex_ext/apex_src/tests/test_metadata.c +908 -0
- data/ext/apex_ext/apex_src/tests/test_output.c +1118 -0
- data/ext/apex_ext/apex_src/tests/test_plugins.c +219 -0
- data/ext/apex_ext/apex_src/tests/test_refs.bib +31 -0
- data/ext/apex_ext/apex_src/tests/test_runner.c +244 -0
- data/ext/apex_ext/apex_src/tests/test_syntax_highlight.c +198 -0
- data/ext/apex_ext/apex_src/tests/test_tables.c +862 -0
- data/ext/apex_ext/apex_src/tests/update_benchmarks.sh +9 -0
- data/ext/apex_ext/apex_src/tests/yaml_test.md +13 -0
- data/ext/apex_ext/apex_src/tests.rb +39 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CMakeLists.txt +48 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/COPYING +170 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CheckFileOffsetBits.c +14 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/CheckFileOffsetBits.cmake +43 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/FindAsan.cmake +74 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/Makefile.nmake +38 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/README.md +206 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/api_test/CMakeLists.txt +30 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/api_test/cplusplus.cpp +15 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/api_test/cplusplus.h +16 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/api_test/harness.c +111 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/api_test/harness.h +35 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/api_test/main.c +1169 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/appveyor.yml +21 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-bq-flat.md +16 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-bq-nested.md +13 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-code.md +11 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-fences.md +14 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-heading.md +9 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-hr.md +10 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-html.md +32 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-lheading.md +8 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-list-flat.md +67 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-list-nested.md +36 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-ref-flat.md +15 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/block-ref-nested.md +17 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-autolink.md +14 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-backticks.md +3 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-em-flat.md +5 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-em-nested.md +5 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-em-worst.md +5 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-entity.md +11 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-escape.md +15 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-html.md +44 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-links-flat.md +23 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-links-nested.md +13 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/inline-newlines.md +24 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/lorem1.md +13 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/samples/rawtabs.md +18 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/statistics.py +595 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/bench/stats.py +19 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/benchmarks.md +33 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/changelog.txt +1245 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/data/CaseFolding.txt +1495 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/CMakeLists.txt +119 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.c +508 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/autolink.h +8 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/cmark-gfm-core-extensions.h +54 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/core-extensions.c +27 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/ext_scanners.c +879 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/ext_scanners.h +24 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/ext_scanners.re +92 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/strikethrough.c +167 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/strikethrough.h +9 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.c +917 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/table.h +12 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/tagfilter.c +60 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/tagfilter.h +8 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/tasklist.c +156 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/extensions/tasklist.h +8 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/fuzz/CMakeLists.txt +22 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/fuzz/README.md +12 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/fuzz/fuzz_quadratic.c +91 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/fuzz/fuzz_quadratic_brackets.c +110 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/fuzz/fuzzloop.sh +28 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/man/CMakeLists.txt +10 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/man/make_man_page.py +133 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/man/man1/cmark-gfm.1 +78 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/man/man3/cmark-gfm.3 +1041 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/nmake.bat +1 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/CMakeLists.txt +230 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/arena.c +104 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/blocks.c +1622 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/buffer.c +278 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/buffer.h +116 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/case_fold_switch.inc +4327 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/chunk.h +135 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/cmark-gfm-extension_api.h +737 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/cmark-gfm.h +833 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/cmark-gfm_version.h.in +7 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/cmark.c +55 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/cmark_ctype.c +44 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/cmark_ctype.h +33 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/commonmark.c +514 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/config.h.in +76 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/entities.inc +2138 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/footnotes.c +63 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/footnotes.h +27 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/houdini.h +57 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/houdini_href_e.c +100 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/houdini_html_e.c +66 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/houdini_html_u.c +149 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/html.c +502 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/html.h +27 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/inlines.c +1788 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/inlines.h +29 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/iterator.c +159 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/iterator.h +26 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/latex.c +468 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/libcmark-gfm.pc.in +10 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/linked_list.c +37 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/main.c +328 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/man.c +274 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/map.c +129 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/map.h +44 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/node.c +1045 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/node.h +167 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/parser.h +59 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/plaintext.c +218 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/plugin.c +36 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/plugin.h +34 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/references.c +43 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/references.h +26 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/registry.c +63 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/registry.h +24 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/render.c +213 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/render.h +62 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/scanners.c +14056 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/scanners.h +70 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/scanners.re +365 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/syntax_extension.c +149 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/syntax_extension.h +34 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/utf8.c +317 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/utf8.h +35 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/src/xml.c +182 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/suppressions +10 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/CMakeLists.txt +114 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/afl_test_cases/test.md +49 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/cmark-fuzz.c +58 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/cmark.py +105 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/entity_tests.py +67 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions-full-info-string.txt +0 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions-table-prefer-style-attributes.txt +38 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/extensions.txt +920 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/fuzzing_dictionary +67 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/normalize.py +194 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/pathological_tests.py +160 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/regression.txt +375 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/roundtrip_tests.py +50 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/run-cmark-fuzz +4 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/smart_punct.txt +177 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/spec.txt +10212 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/test/spec_tests.py +152 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/toolchain-mingw32.cmake +17 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/tools/Dockerfile +41 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/tools/appveyor-build.bat +13 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/tools/make_entities_inc.py +32 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/tools/mkcasefold.pl +22 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/tools/xml2md.xsl +319 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/tools/xml2md_gfm.xsl +80 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/why-cmark-and-not-x.md +104 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/wrappers/wrapper.js +6 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/wrappers/wrapper.py +37 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/wrappers/wrapper.rb +15 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/wrappers/wrapper.rkt +208 -0
- data/ext/apex_ext/apex_src/vendor/cmark-gfm/wrappers/wrapper_ext.py +109 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/CMakeLists.txt +160 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/Changes +372 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/License +20 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/Makefile.am +51 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/ReadMe.md +46 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/announcement.msg +89 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/bootstrap +3 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/cmake/config.h.in +4 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/configure.ac +73 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/doc/doxygen.cfg +222 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/docker/README.mkd +17 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/docker/alpine-3.7 +26 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/docker/fedora-25 +26 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/docker/ubuntu-14.04 +29 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/docker/ubuntu-16.04 +24 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/anchors.yaml +10 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/array.yaml +2 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/global-tag.yaml +14 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/json.yaml +1 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/mapping.yaml +2 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/numbers.yaml +1 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/strings.yaml +7 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/tags.yaml +7 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/examples/yaml-version.yaml +3 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/include/Makefile.am +17 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/include/yaml.h +1999 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/pkg/ReadMe.md +77 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/pkg/docker/Dockerfile +32 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/pkg/docker/output/ReadMe +1 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/pkg/docker/scripts/libyaml-dist.sh +23 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/regression-inputs/clusterfuzz-testcase-minimized-5607885063061504.yml +1 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/Makefile.am +4 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/api.c +1393 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/dumper.c +394 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/emitter.c +2358 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/loader.c +544 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/parser.c +1416 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/reader.c +469 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/scanner.c +3598 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/writer.c +141 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/src/yaml_private.h +684 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/CMakeLists.txt +27 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/Makefile.am +9 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/ReadMe.md +63 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/example-deconstructor-alt.c +800 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/example-deconstructor.c +1127 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/example-reformatter-alt.c +217 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/example-reformatter.c +202 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-all-tests.sh +29 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-dumper.c +314 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-emitter-test-suite.c +290 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-emitter.c +327 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-loader.c +63 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-parser-test-suite.c +196 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-parser.c +88 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/run-scanner.c +63 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/test-reader.c +354 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/tests/test-version.c +29 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/yaml-0.1.pc.in +10 -0
- data/ext/apex_ext/apex_src/vendor/libyaml/yamlConfig.cmake.in +16 -0
- data/ext/apex_ext/extconf.rb +103 -0
- data/lib/apex/configurable.rb +46 -0
- data/lib/apex/document.rb +66 -0
- data/lib/apex/version.rb +15 -0
- data/lib/apex.rb +28 -0
- metadata +544 -0
|
@@ -0,0 +1,2116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extensions Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
#include "test_helpers.h"
|
|
6
|
+
#include "apex/apex.h"
|
|
7
|
+
#include "../src/extensions/advanced_footnotes.h"
|
|
8
|
+
#include <string.h>
|
|
9
|
+
|
|
10
|
+
void test_math(void) {
|
|
11
|
+
int suite_failures = suite_start();
|
|
12
|
+
print_suite_title("Math Support Tests", false, true);
|
|
13
|
+
|
|
14
|
+
apex_options opts = apex_options_default();
|
|
15
|
+
opts.enable_math = true;
|
|
16
|
+
char *html;
|
|
17
|
+
|
|
18
|
+
/* Test inline math */
|
|
19
|
+
html = apex_markdown_to_html("Equation: $E=mc^2$", 18, &opts);
|
|
20
|
+
assert_contains(html, "class=\"math inline\"", "Inline math class");
|
|
21
|
+
assert_contains(html, "E=mc^2", "Math content preserved");
|
|
22
|
+
apex_free_string(html);
|
|
23
|
+
|
|
24
|
+
/* Test display math */
|
|
25
|
+
html = apex_markdown_to_html("$$x^2 + y^2 = z^2$$", 19, &opts);
|
|
26
|
+
assert_contains(html, "class=\"math display\"", "Display math class");
|
|
27
|
+
apex_free_string(html);
|
|
28
|
+
|
|
29
|
+
/* Test that regular dollars don't trigger */
|
|
30
|
+
html = apex_markdown_to_html("I have $5 and $10", 17, &opts);
|
|
31
|
+
if (strstr(html, "class=\"math") == NULL) {
|
|
32
|
+
test_result(true, "Dollar signs don't false trigger");
|
|
33
|
+
} else {
|
|
34
|
+
test_result(false, "Dollar signs false triggered");
|
|
35
|
+
}
|
|
36
|
+
apex_free_string(html);
|
|
37
|
+
|
|
38
|
+
/* Test that math/autolinks are not applied inside Liquid {% %} tags */
|
|
39
|
+
const char *liquid_md = "Before {% kbd $@3 %} after";
|
|
40
|
+
html = apex_markdown_to_html(liquid_md, strlen(liquid_md), &opts);
|
|
41
|
+
assert_contains(html, "{% kbd $@3 %}", "Liquid tag content preserved exactly");
|
|
42
|
+
assert_not_contains(html, "class=\"math", "No math span created inside Liquid tag");
|
|
43
|
+
assert_not_contains(html, "mailto:", "No email autolink created inside Liquid tag");
|
|
44
|
+
apex_free_string(html);
|
|
45
|
+
|
|
46
|
+
bool had_failures = suite_end(suite_failures);
|
|
47
|
+
print_suite_title("Math Support Tests", had_failures, false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Test Critic Markup
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
void test_critic_markup(void) {
|
|
55
|
+
int suite_failures = suite_start();
|
|
56
|
+
print_suite_title("Critic Markup Tests", false, true);
|
|
57
|
+
|
|
58
|
+
apex_options opts = apex_options_default();
|
|
59
|
+
opts.enable_critic_markup = true;
|
|
60
|
+
opts.critic_mode = 2; /* CRITIC_MARKUP */
|
|
61
|
+
char *html;
|
|
62
|
+
|
|
63
|
+
/* Test addition - markup mode */
|
|
64
|
+
html = apex_markdown_to_html("Text {++added++} here", 21, &opts);
|
|
65
|
+
assert_contains(html, "<ins class=\"critic\">added</ins>", "Critic addition markup");
|
|
66
|
+
apex_free_string(html);
|
|
67
|
+
|
|
68
|
+
/* Test deletion - markup mode */
|
|
69
|
+
html = apex_markdown_to_html("Text {--deleted--} here", 23, &opts);
|
|
70
|
+
assert_contains(html, "<del class=\"critic\">deleted</del>", "Critic deletion markup");
|
|
71
|
+
apex_free_string(html);
|
|
72
|
+
|
|
73
|
+
/* Test highlight - markup mode */
|
|
74
|
+
html = apex_markdown_to_html("Text {==highlighted==} here", 27, &opts);
|
|
75
|
+
assert_contains(html, "<mark class=\"critic\">highlighted</mark>", "Critic highlight markup");
|
|
76
|
+
apex_free_string(html);
|
|
77
|
+
|
|
78
|
+
/* Test accept mode - apply all changes */
|
|
79
|
+
opts.critic_mode = 0; /* CRITIC_ACCEPT */
|
|
80
|
+
html = apex_markdown_to_html("Text {++added++} and {--deleted--} more {~~old~>new~~} done.", 61, &opts);
|
|
81
|
+
assert_contains(html, "added", "Accept mode includes additions");
|
|
82
|
+
assert_contains(html, "new", "Accept mode includes new text from substitution");
|
|
83
|
+
/* Should NOT contain markup tags or deleted text */
|
|
84
|
+
if (strstr(html, "<ins") == NULL && strstr(html, "<del") == NULL && strstr(html, "deleted") == NULL && strstr(html, "old") == NULL) {
|
|
85
|
+
test_result(true, "Accept mode removes markup and deletions");
|
|
86
|
+
} else {
|
|
87
|
+
test_result(false, "Accept mode has markup or deleted text");
|
|
88
|
+
}
|
|
89
|
+
apex_free_string(html);
|
|
90
|
+
|
|
91
|
+
/* Test reject mode - revert all changes */
|
|
92
|
+
opts.critic_mode = 1; /* CRITIC_REJECT */
|
|
93
|
+
html = apex_markdown_to_html("Text {++added++} and {--deleted--} more {~~old~>new~~} done.", 61, &opts);
|
|
94
|
+
assert_contains(html, "deleted", "Reject mode includes deletions");
|
|
95
|
+
assert_contains(html, "old", "Reject mode includes old text from substitution");
|
|
96
|
+
/* Should NOT contain markup tags or additions */
|
|
97
|
+
if (strstr(html, "<ins") == NULL && strstr(html, "<del") == NULL && strstr(html, "added") == NULL && strstr(html, "new") == NULL) {
|
|
98
|
+
tests_passed++;
|
|
99
|
+
tests_run++;
|
|
100
|
+
if (!errors_only_output) {
|
|
101
|
+
printf(COLOR_GREEN "✓" COLOR_RESET " Reject mode removes markup and additions\n");
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
tests_failed++;
|
|
105
|
+
tests_run++;
|
|
106
|
+
printf(COLOR_RED "✗" COLOR_RESET " Reject mode has markup or added text\n");
|
|
107
|
+
}
|
|
108
|
+
apex_free_string(html);
|
|
109
|
+
|
|
110
|
+
/* Test accept mode with comments and highlights */
|
|
111
|
+
opts.critic_mode = 0; /* CRITIC_ACCEPT */
|
|
112
|
+
html = apex_markdown_to_html("Text {==highlight==} and {>>comment<<} here.", 44, &opts);
|
|
113
|
+
assert_contains(html, "highlight", "Accept mode keeps highlights");
|
|
114
|
+
/* Comments should be removed */
|
|
115
|
+
if (strstr(html, "comment") == NULL) {
|
|
116
|
+
test_result(true, "Accept mode removes comments");
|
|
117
|
+
} else {
|
|
118
|
+
test_result(false, "Accept mode kept comment");
|
|
119
|
+
}
|
|
120
|
+
apex_free_string(html);
|
|
121
|
+
|
|
122
|
+
/* Test reject mode with comments and highlights */
|
|
123
|
+
opts.critic_mode = 1; /* CRITIC_REJECT */
|
|
124
|
+
html = apex_markdown_to_html("Text {==highlight==} and {>>comment<<} here.", 44, &opts);
|
|
125
|
+
/* Highlights should show text, comments should be removed, no markup tags */
|
|
126
|
+
assert_contains(html, "highlight", "Reject mode shows highlight text");
|
|
127
|
+
if (strstr(html, "comment") == NULL && strstr(html, "<mark") == NULL && strstr(html, "<span") == NULL) {
|
|
128
|
+
test_result(true, "Reject mode removes comments and markup tags");
|
|
129
|
+
} else {
|
|
130
|
+
test_result(false, "Reject mode has comments or markup tags");
|
|
131
|
+
}
|
|
132
|
+
apex_free_string(html);
|
|
133
|
+
|
|
134
|
+
bool had_failures = suite_end(suite_failures);
|
|
135
|
+
print_suite_title("Critic Markup Tests", had_failures, false);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Test processor modes
|
|
140
|
+
*/
|
|
141
|
+
|
|
142
|
+
void test_processor_modes(void) {
|
|
143
|
+
int suite_failures = suite_start();
|
|
144
|
+
print_suite_title("Processor Modes Tests", false, true);
|
|
145
|
+
|
|
146
|
+
const char *markdown = "# Test\n\n**bold**";
|
|
147
|
+
char *html;
|
|
148
|
+
|
|
149
|
+
/* Test CommonMark mode */
|
|
150
|
+
apex_options cm_opts = apex_options_for_mode(APEX_MODE_COMMONMARK);
|
|
151
|
+
html = apex_markdown_to_html(markdown, strlen(markdown), &cm_opts);
|
|
152
|
+
assert_contains(html, "<h1", "CommonMark mode works");
|
|
153
|
+
apex_free_string(html);
|
|
154
|
+
|
|
155
|
+
/* Test GFM mode */
|
|
156
|
+
apex_options gfm_opts = apex_options_for_mode(APEX_MODE_GFM);
|
|
157
|
+
html = apex_markdown_to_html(markdown, strlen(markdown), &gfm_opts);
|
|
158
|
+
assert_contains(html, "<strong>bold</strong>", "GFM mode works");
|
|
159
|
+
apex_free_string(html);
|
|
160
|
+
|
|
161
|
+
/* Test MultiMarkdown mode */
|
|
162
|
+
apex_options mmd_opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
163
|
+
html = apex_markdown_to_html(markdown, strlen(markdown), &mmd_opts);
|
|
164
|
+
assert_contains(html, "<h1", "MultiMarkdown mode works");
|
|
165
|
+
apex_free_string(html);
|
|
166
|
+
|
|
167
|
+
/* Test Unified mode */
|
|
168
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
169
|
+
html = apex_markdown_to_html(markdown, strlen(markdown), &unified_opts);
|
|
170
|
+
assert_contains(html, "<h1", "Unified mode works");
|
|
171
|
+
apex_free_string(html);
|
|
172
|
+
|
|
173
|
+
bool had_failures = suite_end(suite_failures);
|
|
174
|
+
print_suite_title("Processor Modes Tests", had_failures, false);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Test MultiMarkdown-style image attributes (inline and reference)
|
|
179
|
+
*/
|
|
180
|
+
|
|
181
|
+
void test_multimarkdown_image_attributes(void) {
|
|
182
|
+
int suite_failures = suite_start();
|
|
183
|
+
print_suite_title("MultiMarkdown Image Attribute Tests", false, true);
|
|
184
|
+
|
|
185
|
+
apex_options mmd_opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
186
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
187
|
+
|
|
188
|
+
const char *md =
|
|
189
|
+
"\n\n"
|
|
190
|
+
"\n\n"
|
|
191
|
+
"\n\n"
|
|
192
|
+
"\n\n"
|
|
193
|
+
"![Ref with attrs][ref-inline-1]\n\n"
|
|
194
|
+
"[ref-inline-1]: /images/test-ref-1.jpg width=200\n\n"
|
|
195
|
+
"![Ref with title][ref-inline-2]\n\n"
|
|
196
|
+
"[ref-inline-2]: /images/test-ref-2.jpg \"Falafel\" width=300\n\n"
|
|
197
|
+
"![Ref percent][ref-inline-3]\n\n"
|
|
198
|
+
"[ref-inline-3]: /images/test-ref-3.jpg width=50%\n\n"
|
|
199
|
+
"![Ref classes][ref-inline-4]\n\n"
|
|
200
|
+
"[ref-inline-4]: /images/test-ref-4.jpg \"Caption\" class=center shadow width=250 height=60%\n";
|
|
201
|
+
|
|
202
|
+
/* Helper lambda-style macro to run assertions in a given mode */
|
|
203
|
+
#define RUN_IMAGE_ATTR_TESTS(OPTS, MODE_LABEL) \
|
|
204
|
+
do { \
|
|
205
|
+
char *html = apex_markdown_to_html(md, strlen(md), &(OPTS)); \
|
|
206
|
+
assert_contains(html, "src=\"/images/test-inline-1.jpg\"", MODE_LABEL " inline url 1"); \
|
|
207
|
+
assert_contains(html, "width=\"200\"", MODE_LABEL " inline width=200"); \
|
|
208
|
+
assert_contains(html, "src=\"/images/test-inline-2.jpg\"", MODE_LABEL " inline url 2"); \
|
|
209
|
+
assert_contains(html, "title=\"Falafel\"", MODE_LABEL " inline title"); \
|
|
210
|
+
assert_contains(html, "width=\"300\"", MODE_LABEL " inline width=300"); \
|
|
211
|
+
assert_contains(html, "src=\"/images/test-inline-3.jpg\"", MODE_LABEL " inline url 3"); \
|
|
212
|
+
assert_contains(html, "style=\"width: 50%\"", MODE_LABEL " inline width 50% style"); \
|
|
213
|
+
assert_contains(html, "src=\"/images/test-inline-4.jpg\"", MODE_LABEL " inline url 4"); \
|
|
214
|
+
/* Class list ordering is not guaranteed; just check for center */ \
|
|
215
|
+
assert_contains(html, "class=\"center", MODE_LABEL " inline center class"); \
|
|
216
|
+
assert_contains(html, "width=\"250\"", MODE_LABEL " inline width=250"); \
|
|
217
|
+
assert_contains(html, "height: 60%", MODE_LABEL " inline height 60% style"); \
|
|
218
|
+
assert_contains(html, "src=\"/images/test-ref-1.jpg\"", MODE_LABEL " ref url 1"); \
|
|
219
|
+
assert_contains(html, "width=\"200\"", MODE_LABEL " ref width=200"); \
|
|
220
|
+
assert_contains(html, "src=\"/images/test-ref-2.jpg\"", MODE_LABEL " ref url 2"); \
|
|
221
|
+
assert_contains(html, "title=\"Falafel\"", MODE_LABEL " ref title"); \
|
|
222
|
+
assert_contains(html, "width=\"300\"", MODE_LABEL " ref width=300"); \
|
|
223
|
+
assert_contains(html, "src=\"/images/test-ref-3.jpg\"", MODE_LABEL " ref url 3"); \
|
|
224
|
+
assert_contains(html, "style=\"width: 50%\"", MODE_LABEL " ref width 50% style"); \
|
|
225
|
+
assert_contains(html, "src=\"/images/test-ref-4.jpg\"", MODE_LABEL " ref url 4"); \
|
|
226
|
+
assert_contains(html, "class=\"center", MODE_LABEL " ref center class"); \
|
|
227
|
+
assert_contains(html, "width=\"250\"", MODE_LABEL " ref width=250"); \
|
|
228
|
+
assert_contains(html, "height: 60%", MODE_LABEL " ref height 60% style"); \
|
|
229
|
+
apex_free_string(html); \
|
|
230
|
+
} while (0)
|
|
231
|
+
|
|
232
|
+
RUN_IMAGE_ATTR_TESTS(mmd_opts, "MMD");
|
|
233
|
+
RUN_IMAGE_ATTR_TESTS(unified_opts, "Unified");
|
|
234
|
+
|
|
235
|
+
#undef RUN_IMAGE_ATTR_TESTS
|
|
236
|
+
|
|
237
|
+
/* Test @2x srcset:  and  emit srcset="url 1x, url@2x 2x" */
|
|
238
|
+
{
|
|
239
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
240
|
+
const char *at2x_inline = "";
|
|
241
|
+
char *html = apex_markdown_to_html(at2x_inline, strlen(at2x_inline), &opts);
|
|
242
|
+
assert_contains(html, "src=\"img/icon_512x512.png\"", "@2x inline: src present");
|
|
243
|
+
assert_contains(html, "srcset=\"img/icon_512x512.png 1x, img/icon_512x512@2x.png 2x\"", "@2x inline: srcset 1x and 2x");
|
|
244
|
+
apex_free_string(html);
|
|
245
|
+
|
|
246
|
+
const char *at2x_title = "";
|
|
247
|
+
html = apex_markdown_to_html(at2x_title, strlen(at2x_title), &opts);
|
|
248
|
+
assert_contains(html, "srcset=\"img/icon_512x512.png 1x, img/icon_512x512@2x.png 2x\"", "@2x with title: srcset");
|
|
249
|
+
apex_free_string(html);
|
|
250
|
+
|
|
251
|
+
/* Reference-style: [ref]: url @2x */
|
|
252
|
+
const char *at2x_ref = "![Logo][logo]\n\n[logo]: img/hero.png @2x";
|
|
253
|
+
html = apex_markdown_to_html(at2x_ref, strlen(at2x_ref), &opts);
|
|
254
|
+
assert_contains(html, "srcset=\"img/hero.png 1x, img/hero@2x.png 2x\"", "@2x reference: srcset");
|
|
255
|
+
apex_free_string(html);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Reference-style image with attributes between two @2x images:
|
|
259
|
+
* - First image: inline with @2x, should get srcset
|
|
260
|
+
* - Middle image: reference-style with width/height/style, no @2x, should get attributes but no srcset
|
|
261
|
+
* - Last image: inline with @2x, should get srcset
|
|
262
|
+
* This guards against @2x or index bookkeeping causing the middle image to lose its attributes.
|
|
263
|
+
*/
|
|
264
|
+
{
|
|
265
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
266
|
+
const char *three_img_md =
|
|
267
|
+
"\n\n"
|
|
268
|
+
"![Badge][badge]\n\n"
|
|
269
|
+
"[badge]: img/badge.png width=250 height=83 style=\"margin: 0 auto;\"\n\n"
|
|
270
|
+
"\n";
|
|
271
|
+
|
|
272
|
+
char *html = apex_markdown_to_html(three_img_md, strlen(three_img_md), &opts);
|
|
273
|
+
|
|
274
|
+
/* First image: has srcset with @2x */
|
|
275
|
+
assert_contains(html,
|
|
276
|
+
"src=\"img/first.png\"",
|
|
277
|
+
"@2x three-image: first src present");
|
|
278
|
+
assert_contains(html,
|
|
279
|
+
"srcset=\"img/first.png 1x, img/first@2x.png 2x\"",
|
|
280
|
+
"@2x three-image: first srcset present");
|
|
281
|
+
|
|
282
|
+
/* Middle (badge) image: has width/height/style, but no srcset */
|
|
283
|
+
assert_contains(html,
|
|
284
|
+
"src=\"img/badge.png\"",
|
|
285
|
+
"@2x three-image: middle src present");
|
|
286
|
+
assert_contains(html,
|
|
287
|
+
"width=\"250\"",
|
|
288
|
+
"@2x three-image: middle width attribute");
|
|
289
|
+
assert_contains(html,
|
|
290
|
+
"height=\"83\"",
|
|
291
|
+
"@2x three-image: middle height attribute");
|
|
292
|
+
assert_contains(html,
|
|
293
|
+
"style=\"margin: 0 auto;\"",
|
|
294
|
+
"@2x three-image: middle style attribute");
|
|
295
|
+
assert_not_contains(html,
|
|
296
|
+
"img/badge@2x.png",
|
|
297
|
+
"@2x three-image: middle has no @2x srcset");
|
|
298
|
+
|
|
299
|
+
/* Last image: has srcset with @2x */
|
|
300
|
+
assert_contains(html,
|
|
301
|
+
"src=\"img/last.png\"",
|
|
302
|
+
"@2x three-image: last src present");
|
|
303
|
+
assert_contains(html,
|
|
304
|
+
"srcset=\"img/last.png 1x, img/last@2x.png 2x\"",
|
|
305
|
+
"@2x three-image: last srcset present");
|
|
306
|
+
|
|
307
|
+
apex_free_string(html);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* @3x marker: behaves like @2x but emits both 2x and 3x entries in srcset */
|
|
311
|
+
{
|
|
312
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
313
|
+
const char *at3x_inline = "";
|
|
314
|
+
char *html = apex_markdown_to_html(at3x_inline, strlen(at3x_inline), &opts);
|
|
315
|
+
assert_contains(html, "src=\"img/icon_512x512.png\"", "@3x inline: src present");
|
|
316
|
+
assert_contains(html,
|
|
317
|
+
"srcset=\"img/icon_512x512.png 1x, img/icon_512x512@2x.png 2x, img/icon_512x512@3x.png 3x\"",
|
|
318
|
+
"@3x inline: srcset 1x, 2x, 3x");
|
|
319
|
+
apex_free_string(html);
|
|
320
|
+
|
|
321
|
+
/* Reference-style: [ref]: url @3x */
|
|
322
|
+
const char *at3x_ref = "![Logo][logo3]\n\n[logo3]: img/hero3.png @3x";
|
|
323
|
+
html = apex_markdown_to_html(at3x_ref, strlen(at3x_ref), &opts);
|
|
324
|
+
assert_contains(html,
|
|
325
|
+
"srcset=\"img/hero3.png 1x, img/hero3@2x.png 2x, img/hero3@3x.png 3x\"",
|
|
326
|
+
"@3x reference: srcset 1x, 2x, 3x");
|
|
327
|
+
apex_free_string(html);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
bool had_failures = suite_end(suite_failures);
|
|
331
|
+
print_suite_title("MultiMarkdown Image Attribute Tests", had_failures, false);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Test file includes
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
void test_file_includes(void) {
|
|
339
|
+
int suite_failures = suite_start();
|
|
340
|
+
print_suite_title("File Includes Tests", false, true);
|
|
341
|
+
|
|
342
|
+
apex_options opts = apex_options_default();
|
|
343
|
+
opts.enable_file_includes = true;
|
|
344
|
+
#ifdef TEST_FIXTURES_DIR
|
|
345
|
+
opts.base_directory = TEST_FIXTURES_DIR;
|
|
346
|
+
#else
|
|
347
|
+
opts.base_directory = "tests/fixtures/includes";
|
|
348
|
+
#endif
|
|
349
|
+
char *html;
|
|
350
|
+
|
|
351
|
+
/* Test Marked markdown include */
|
|
352
|
+
html = apex_markdown_to_html("Before\n\n<<[simple.md]\n\nAfter", 28, &opts);
|
|
353
|
+
assert_contains(html, "Included Content", "Marked markdown include");
|
|
354
|
+
assert_contains(html, "List item 1", "Markdown processed from include");
|
|
355
|
+
apex_free_string(html);
|
|
356
|
+
|
|
357
|
+
/* Test Marked code include */
|
|
358
|
+
html = apex_markdown_to_html("Code:\n\n<<(code.py)\n\nDone", 23, &opts);
|
|
359
|
+
assert_contains(html, "<pre", "Code include generates pre tag");
|
|
360
|
+
assert_contains(html, "def hello", "Code content included");
|
|
361
|
+
assert_contains(html, "lang=\"python\"", "Python language class added");
|
|
362
|
+
apex_free_string(html);
|
|
363
|
+
|
|
364
|
+
/* Test Marked raw HTML include - currently uses placeholder */
|
|
365
|
+
html = apex_markdown_to_html("HTML:\n\n<<{raw.html}\n\nDone", 24, &opts);
|
|
366
|
+
assert_contains(html, "APEX_RAW_INCLUDE", "Raw HTML include marker present");
|
|
367
|
+
apex_free_string(html);
|
|
368
|
+
|
|
369
|
+
/* Test MMD transclusion */
|
|
370
|
+
html = apex_markdown_to_html("Include: {{simple.md}}", 22, &opts);
|
|
371
|
+
assert_contains(html, "Included Content", "MMD transclusion works");
|
|
372
|
+
apex_free_string(html);
|
|
373
|
+
|
|
374
|
+
/* Test MMD wildcard transclusion: file.* (legacy behavior) */
|
|
375
|
+
html = apex_markdown_to_html("Include: {{simple.*}}", 22, &opts);
|
|
376
|
+
assert_contains(html, "Included Content", "MMD wildcard file.* resolves to simple.md");
|
|
377
|
+
apex_free_string(html);
|
|
378
|
+
|
|
379
|
+
/* Test CSV to table conversion */
|
|
380
|
+
html = apex_markdown_to_html("Data:\n\n<<[data.csv]\n\nEnd", 24, &opts);
|
|
381
|
+
assert_contains(html, "<table>", "CSV converts to table");
|
|
382
|
+
assert_contains(html, "Alice", "CSV data in table");
|
|
383
|
+
assert_contains(html, "New York", "CSV cell content");
|
|
384
|
+
apex_free_string(html);
|
|
385
|
+
|
|
386
|
+
/* Test TSV to table conversion */
|
|
387
|
+
html = apex_markdown_to_html("{{data.tsv}}", 12, &opts);
|
|
388
|
+
assert_contains(html, "<table>", "TSV converts to table");
|
|
389
|
+
assert_contains(html, "Widget", "TSV data in table");
|
|
390
|
+
apex_free_string(html);
|
|
391
|
+
|
|
392
|
+
/* Test iA Writer image include */
|
|
393
|
+
html = apex_markdown_to_html("/image.png", 10, &opts);
|
|
394
|
+
assert_contains(html, "<img", "iA Writer image include");
|
|
395
|
+
assert_contains(html, "image.png", "Image path included");
|
|
396
|
+
apex_free_string(html);
|
|
397
|
+
|
|
398
|
+
/* Test iA Writer code include */
|
|
399
|
+
html = apex_markdown_to_html("/code.py", 8, &opts);
|
|
400
|
+
assert_contains(html, "<pre", "iA Writer code include");
|
|
401
|
+
assert_contains(html, "def hello", "Code included");
|
|
402
|
+
apex_free_string(html);
|
|
403
|
+
|
|
404
|
+
/* Test glob wildcard: *.md (should resolve to one of the .md fixtures) */
|
|
405
|
+
html = apex_markdown_to_html("{{*.md}}", 10, &opts);
|
|
406
|
+
if (strstr(html, "Included Content") != NULL ||
|
|
407
|
+
strstr(html, "Nested Content") != NULL) {
|
|
408
|
+
tests_passed++;
|
|
409
|
+
tests_run++;
|
|
410
|
+
if (!errors_only_output) {
|
|
411
|
+
printf(COLOR_GREEN "✓" COLOR_RESET " Glob wildcard *.md resolves to a Markdown file\n");
|
|
412
|
+
}
|
|
413
|
+
} else {
|
|
414
|
+
tests_failed++;
|
|
415
|
+
tests_run++;
|
|
416
|
+
test_result(false, "Glob wildcard *.md did not resolve correctly");
|
|
417
|
+
}
|
|
418
|
+
apex_free_string(html);
|
|
419
|
+
|
|
420
|
+
/* Test MMD address syntax - line range */
|
|
421
|
+
html = apex_markdown_to_html("{{simple.md}}[3,5]", 20, &opts);
|
|
422
|
+
assert_contains(html, "This is a simple", "Line range includes line 3");
|
|
423
|
+
assert_contains(html, "markdown file", "Line range includes line 4");
|
|
424
|
+
assert_not_contains(html, "Included Content", "Line range excludes line 1");
|
|
425
|
+
assert_not_contains(html, "List item 1", "Line range excludes line 5 and beyond");
|
|
426
|
+
apex_free_string(html);
|
|
427
|
+
|
|
428
|
+
/* Test MMD address syntax - from line to end */
|
|
429
|
+
html = apex_markdown_to_html("{{simple.md}}[5,]", 19, &opts);
|
|
430
|
+
assert_contains(html, "List item 1", "From line includes line 5");
|
|
431
|
+
assert_contains(html, "List item 2", "From line includes later lines");
|
|
432
|
+
assert_not_contains(html, "Included Content", "From line excludes earlier lines");
|
|
433
|
+
apex_free_string(html);
|
|
434
|
+
|
|
435
|
+
/* Test MMD address syntax - prefix */
|
|
436
|
+
html = apex_markdown_to_html("{{code.py}}[1,3;prefix=\"C: \"]", 30, &opts);
|
|
437
|
+
assert_contains(html, "C: def hello()", "Prefix applied to included lines");
|
|
438
|
+
assert_contains(html, "C: print", "Prefix applied to all lines");
|
|
439
|
+
apex_free_string(html);
|
|
440
|
+
|
|
441
|
+
/* Test glob wildcard with single-character ?: c?de.py should resolve to code.py */
|
|
442
|
+
html = apex_markdown_to_html("{{c?de.py}}", 12, &opts);
|
|
443
|
+
assert_contains(html, "def hello", "? wildcard resolves to code.py");
|
|
444
|
+
apex_free_string(html);
|
|
445
|
+
|
|
446
|
+
/* Test Marked address syntax - line range */
|
|
447
|
+
html = apex_markdown_to_html("<<[simple.md][3,5]", 20, &opts);
|
|
448
|
+
assert_contains(html, "This is a simple", "Marked syntax with line range");
|
|
449
|
+
assert_not_contains(html, "Included Content", "Line range excludes header");
|
|
450
|
+
apex_free_string(html);
|
|
451
|
+
|
|
452
|
+
/* Test Marked code include with address syntax */
|
|
453
|
+
html = apex_markdown_to_html("<<(code.py)[1,3]", 18, &opts);
|
|
454
|
+
assert_contains(html, "def hello()", "Code include with line range");
|
|
455
|
+
assert_contains(html, "print", "Code include includes second line");
|
|
456
|
+
assert_not_contains(html, "return True", "Code include excludes later lines");
|
|
457
|
+
apex_free_string(html);
|
|
458
|
+
|
|
459
|
+
/* Test regex address syntax */
|
|
460
|
+
html = apex_markdown_to_html("{{simple.md}}[/This is/,/List item/]", 36, &opts);
|
|
461
|
+
assert_contains(html, "This is a simple", "Regex range includes matching line");
|
|
462
|
+
assert_contains(html, "markdown file", "Regex range includes lines between matches");
|
|
463
|
+
assert_not_contains(html, "Included Content", "Regex range excludes before first match");
|
|
464
|
+
apex_free_string(html);
|
|
465
|
+
|
|
466
|
+
/* Verify iA Writer syntax is NOT affected (no address syntax) */
|
|
467
|
+
html = apex_markdown_to_html("/code.py", 8, &opts);
|
|
468
|
+
assert_contains(html, "def hello()", "iA Writer syntax unchanged");
|
|
469
|
+
assert_contains(html, "return True", "iA Writer includes full file");
|
|
470
|
+
apex_free_string(html);
|
|
471
|
+
|
|
472
|
+
/* Test address syntax edge cases */
|
|
473
|
+
/* Single line range - line 3 is the full sentence, so [3,4] includes only line 3 */
|
|
474
|
+
html = apex_markdown_to_html("{{simple.md}}[3,4]", 20, &opts);
|
|
475
|
+
assert_contains(html, "This is a simple", "Single line range works");
|
|
476
|
+
assert_contains(html, "markdown file", "Single line includes full line 3");
|
|
477
|
+
assert_not_contains(html, "List item 1", "Single line excludes line 5");
|
|
478
|
+
apex_free_string(html);
|
|
479
|
+
|
|
480
|
+
/* Prefix with regex range - check if prefix is applied (may need to check implementation) */
|
|
481
|
+
html = apex_markdown_to_html("{{simple.md}}[/This is/,/List item/;prefix=\" \"]", 48, &opts);
|
|
482
|
+
assert_contains(html, "This is a simple", "Regex range includes matching line");
|
|
483
|
+
/* Prefix application to regex ranges may need implementation verification */
|
|
484
|
+
apex_free_string(html);
|
|
485
|
+
|
|
486
|
+
/* Prefix only (no line range) - verify prefix-only syntax is parsed */
|
|
487
|
+
html = apex_markdown_to_html("{{code.py}}[prefix=\"// \"]", 26, &opts);
|
|
488
|
+
assert_contains(html, "def hello()", "Prefix-only includes content");
|
|
489
|
+
/* Prefix application may need implementation verification */
|
|
490
|
+
apex_free_string(html);
|
|
491
|
+
|
|
492
|
+
/* Address syntax with CSV (should extract lines before conversion) */
|
|
493
|
+
html = apex_markdown_to_html("{{data.csv}}[2,4]", 18, &opts);
|
|
494
|
+
assert_contains(html, "<table>", "CSV with address converts to table");
|
|
495
|
+
assert_contains(html, "Alice", "CSV address includes correct row");
|
|
496
|
+
assert_not_contains(html, "Name,Age,City", "CSV address excludes header");
|
|
497
|
+
apex_free_string(html);
|
|
498
|
+
|
|
499
|
+
/* Address syntax with Marked raw HTML */
|
|
500
|
+
html = apex_markdown_to_html("<<{raw.html}[1,3]", 18, &opts);
|
|
501
|
+
assert_contains(html, "APEX_RAW_INCLUDE", "Raw HTML include with address");
|
|
502
|
+
apex_free_string(html);
|
|
503
|
+
|
|
504
|
+
/* Regex with no match (should return empty) */
|
|
505
|
+
html = apex_markdown_to_html("{{simple.md}}[/NOTFOUND/,/ALSONOTFOUND/]", 44, &opts);
|
|
506
|
+
/* Should not contain any content from file */
|
|
507
|
+
if (strstr(html, "Included Content") == NULL && strstr(html, "List item") == NULL) {
|
|
508
|
+
tests_passed++;
|
|
509
|
+
tests_run++;
|
|
510
|
+
if (!errors_only_output) {
|
|
511
|
+
printf(COLOR_GREEN "✓" COLOR_RESET " Regex with no match returns empty\n");
|
|
512
|
+
}
|
|
513
|
+
} else {
|
|
514
|
+
tests_failed++;
|
|
515
|
+
tests_run++;
|
|
516
|
+
test_result(false, "Regex with no match should return empty");
|
|
517
|
+
}
|
|
518
|
+
apex_free_string(html);
|
|
519
|
+
|
|
520
|
+
bool had_failures = suite_end(suite_failures);
|
|
521
|
+
print_suite_title("File Includes Tests", had_failures, false);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Test IAL (Inline Attribute Lists)
|
|
526
|
+
*/
|
|
527
|
+
|
|
528
|
+
void test_definition_lists(void) {
|
|
529
|
+
int suite_failures = suite_start();
|
|
530
|
+
print_suite_title("Definition Lists Tests", false, true);
|
|
531
|
+
|
|
532
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_KRAMDOWN);
|
|
533
|
+
char *html;
|
|
534
|
+
|
|
535
|
+
/* Test basic definition list */
|
|
536
|
+
html = apex_markdown_to_html("Term\n: Definition", 17, &opts);
|
|
537
|
+
assert_contains(html, "<dl>", "Definition list tag");
|
|
538
|
+
assert_contains(html, "<dt>Term</dt>", "Definition term");
|
|
539
|
+
assert_contains(html, "<dd>Definition</dd>", "Definition description");
|
|
540
|
+
apex_free_string(html);
|
|
541
|
+
|
|
542
|
+
/* Test multiple definitions */
|
|
543
|
+
html = apex_markdown_to_html("Apple\n: A fruit\n: A company", 27, &opts);
|
|
544
|
+
assert_contains(html, "<dt>Apple</dt>", "Multiple definitions term");
|
|
545
|
+
assert_contains(html, "<dd>A fruit</dd>", "First definition");
|
|
546
|
+
assert_contains(html, "<dd>A company</dd>", "Second definition");
|
|
547
|
+
apex_free_string(html);
|
|
548
|
+
|
|
549
|
+
/* Test definition with Markdown content */
|
|
550
|
+
const char *block_def = "Term\n: Definition with **bold** and *italic*";
|
|
551
|
+
html = apex_markdown_to_html(block_def, strlen(block_def), &opts);
|
|
552
|
+
assert_contains(html, "<dd>", "Definition created");
|
|
553
|
+
assert_contains(html, "<strong>bold</strong>", "Bold markdown in definition");
|
|
554
|
+
assert_contains(html, "<em>italic</em>", "Italic markdown in definition");
|
|
555
|
+
apex_free_string(html);
|
|
556
|
+
|
|
557
|
+
/* Test multiple terms and definitions */
|
|
558
|
+
const char *multi = "Term1\n: Def1\n\nTerm2\n: Def2";
|
|
559
|
+
html = apex_markdown_to_html(multi, strlen(multi), &opts);
|
|
560
|
+
assert_contains(html, "<dt>Term1</dt>", "First term");
|
|
561
|
+
assert_contains(html, "<dt>Term2</dt>", "Second term");
|
|
562
|
+
assert_contains(html, "<dd>Def1</dd>", "First definition");
|
|
563
|
+
assert_contains(html, "<dd>Def2</dd>", "Second definition");
|
|
564
|
+
apex_free_string(html);
|
|
565
|
+
|
|
566
|
+
/* Test inline links in definition list terms */
|
|
567
|
+
const char *inline_link = "Term with [inline link](https://example.com)\n: Definition";
|
|
568
|
+
html = apex_markdown_to_html(inline_link, strlen(inline_link), &opts);
|
|
569
|
+
assert_contains(html, "<dt>", "Definition term with inline link");
|
|
570
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Inline link in term has href");
|
|
571
|
+
assert_contains(html, "inline link</a>", "Inline link text in term");
|
|
572
|
+
apex_free_string(html);
|
|
573
|
+
|
|
574
|
+
/* Test reference-style links in definition list terms */
|
|
575
|
+
const char *ref_link = "Term with [reference link][ref]\n: Definition\n\n[ref]: https://example.com \"Reference title\"";
|
|
576
|
+
html = apex_markdown_to_html(ref_link, strlen(ref_link), &opts);
|
|
577
|
+
assert_contains(html, "<dt>", "Definition term with reference link");
|
|
578
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Reference link in term has href");
|
|
579
|
+
assert_contains(html, "title=\"Reference title\"", "Reference link in term has title");
|
|
580
|
+
assert_contains(html, "reference link</a>", "Reference link text in term");
|
|
581
|
+
apex_free_string(html);
|
|
582
|
+
|
|
583
|
+
/* Test shortcut reference links in definition list terms */
|
|
584
|
+
const char *shortcut_link = "Term with [shortcut][]\n: Definition\n\n[shortcut]: https://example.org";
|
|
585
|
+
html = apex_markdown_to_html(shortcut_link, strlen(shortcut_link), &opts);
|
|
586
|
+
assert_contains(html, "<dt>", "Definition term with shortcut reference");
|
|
587
|
+
assert_contains(html, "<a href=\"https://example.org\"", "Shortcut reference in term has href");
|
|
588
|
+
assert_contains(html, "shortcut</a>", "Shortcut reference text in term");
|
|
589
|
+
apex_free_string(html);
|
|
590
|
+
|
|
591
|
+
/* Test inline links in definition descriptions */
|
|
592
|
+
const char *def_inline = "Term\n: Definition with [inline link](https://example.com)";
|
|
593
|
+
html = apex_markdown_to_html(def_inline, strlen(def_inline), &opts);
|
|
594
|
+
assert_contains(html, "<dd>", "Definition with inline link");
|
|
595
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Inline link in definition has href");
|
|
596
|
+
apex_free_string(html);
|
|
597
|
+
|
|
598
|
+
/* Test reference-style links in definition descriptions */
|
|
599
|
+
const char *def_ref = "Term\n: Definition with [reference][ref]\n\n[ref]: https://example.com";
|
|
600
|
+
html = apex_markdown_to_html(def_ref, strlen(def_ref), &opts);
|
|
601
|
+
assert_contains(html, "<dd>", "Definition with reference link");
|
|
602
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Reference link in definition has href");
|
|
603
|
+
apex_free_string(html);
|
|
604
|
+
|
|
605
|
+
/* Test definition list with blank line between term and first definition */
|
|
606
|
+
const char *blank_before = "Term\n\n: definition 1\n: definition 2";
|
|
607
|
+
html = apex_markdown_to_html(blank_before, strlen(blank_before), &opts);
|
|
608
|
+
assert_contains(html, "<dl>", "Definition list with blank before first definition");
|
|
609
|
+
assert_contains(html, "<dt>Term</dt>", "Term preserved across blank line");
|
|
610
|
+
assert_contains(html, "<dd>definition 1</dd>", "First definition after blank line");
|
|
611
|
+
assert_contains(html, "<dd>definition 2</dd>", "Second definition");
|
|
612
|
+
apex_free_string(html);
|
|
613
|
+
|
|
614
|
+
/* Test definition list with blank line between definitions */
|
|
615
|
+
const char *blank_between = "Term\n: definition 1\n\n: definition 2";
|
|
616
|
+
html = apex_markdown_to_html(blank_between, strlen(blank_between), &opts);
|
|
617
|
+
assert_contains(html, "<dl>", "Definition list with blank between definitions");
|
|
618
|
+
assert_contains(html, "<dt>Term</dt>", "Term in list with blank between definitions");
|
|
619
|
+
assert_contains(html, "<dd>definition 1</dd>", "First definition");
|
|
620
|
+
assert_contains(html, "<dd>definition 2</dd>", "Second definition after blank line");
|
|
621
|
+
apex_free_string(html);
|
|
622
|
+
|
|
623
|
+
/* Test definition list with blank lines everywhere (user's exact case) */
|
|
624
|
+
const char *blank_everywhere = "Term\n\n: definition 1\n\n: definition 2";
|
|
625
|
+
html = apex_markdown_to_html(blank_everywhere, strlen(blank_everywhere), &opts);
|
|
626
|
+
assert_contains(html, "<dl>", "Definition list with blank lines everywhere");
|
|
627
|
+
assert_contains(html, "<dt>Term</dt>", "Term preserved with multiple blank lines");
|
|
628
|
+
assert_contains(html, "<dd>definition 1</dd>", "First definition");
|
|
629
|
+
assert_contains(html, "<dd>definition 2</dd>", "Second definition");
|
|
630
|
+
apex_free_string(html);
|
|
631
|
+
|
|
632
|
+
bool had_failures = suite_end(suite_failures);
|
|
633
|
+
print_suite_title("Definition Lists Tests", had_failures, false);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
/**
|
|
637
|
+
* Test advanced tables
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
void test_callouts(void) {
|
|
641
|
+
int suite_failures = suite_start();
|
|
642
|
+
print_suite_title("Callouts Tests", false, true);
|
|
643
|
+
|
|
644
|
+
apex_options opts = apex_options_default();
|
|
645
|
+
opts.enable_callouts = true;
|
|
646
|
+
char *html;
|
|
647
|
+
|
|
648
|
+
/* Test Bear/Obsidian NOTE callout */
|
|
649
|
+
html = apex_markdown_to_html("> [!NOTE] Important\n> This is a note", 36, &opts);
|
|
650
|
+
assert_contains(html, "class=\"callout", "Callout class present");
|
|
651
|
+
assert_contains(html, "callout-note", "Note callout type");
|
|
652
|
+
apex_free_string(html);
|
|
653
|
+
|
|
654
|
+
/* Test WARNING callout */
|
|
655
|
+
html = apex_markdown_to_html("> [!WARNING] Be careful\n> Warning text", 38, &opts);
|
|
656
|
+
assert_contains(html, "callout-warning", "Warning callout type");
|
|
657
|
+
apex_free_string(html);
|
|
658
|
+
|
|
659
|
+
/* Test TIP callout */
|
|
660
|
+
html = apex_markdown_to_html("> [!TIP] Pro tip\n> Helpful advice", 33, &opts);
|
|
661
|
+
assert_contains(html, "callout-tip", "Tip callout type");
|
|
662
|
+
apex_free_string(html);
|
|
663
|
+
|
|
664
|
+
/* Test DANGER callout */
|
|
665
|
+
html = apex_markdown_to_html("> [!DANGER] Critical\n> Dangerous action", 40, &opts);
|
|
666
|
+
assert_contains(html, "callout-danger", "Danger callout type");
|
|
667
|
+
apex_free_string(html);
|
|
668
|
+
|
|
669
|
+
/* Test INFO callout */
|
|
670
|
+
html = apex_markdown_to_html("> [!INFO] Information\n> Info text", 34, &opts);
|
|
671
|
+
assert_contains(html, "callout-info", "Info callout type");
|
|
672
|
+
apex_free_string(html);
|
|
673
|
+
|
|
674
|
+
/* Test collapsible callout with + */
|
|
675
|
+
html = apex_markdown_to_html("> [!NOTE]+ Expandable\n> Content", 32, &opts);
|
|
676
|
+
assert_contains(html, "<details", "Collapsible callout uses details");
|
|
677
|
+
apex_free_string(html);
|
|
678
|
+
|
|
679
|
+
/* Test collapsed callout with - */
|
|
680
|
+
html = apex_markdown_to_html("> [!NOTE]- Collapsed\n> Hidden content", 38, &opts);
|
|
681
|
+
assert_contains(html, "<details", "Collapsed callout uses details");
|
|
682
|
+
apex_free_string(html);
|
|
683
|
+
|
|
684
|
+
/* Test callout with multiple paragraphs */
|
|
685
|
+
const char *multi = "> [!NOTE] Title\n> Para 1\n>\n> Para 2";
|
|
686
|
+
html = apex_markdown_to_html(multi, strlen(multi), &opts);
|
|
687
|
+
assert_contains(html, "callout", "Multi-paragraph callout");
|
|
688
|
+
apex_free_string(html);
|
|
689
|
+
|
|
690
|
+
/* Test regular blockquote (not a callout) */
|
|
691
|
+
html = apex_markdown_to_html("> Just a quote\n> Regular text", 29, &opts);
|
|
692
|
+
if (strstr(html, "class=\"callout") == NULL) {
|
|
693
|
+
test_result(true, "Regular blockquote not treated as callout");
|
|
694
|
+
} else {
|
|
695
|
+
test_result(false, "Regular blockquote incorrectly treated as callout");
|
|
696
|
+
}
|
|
697
|
+
apex_free_string(html);
|
|
698
|
+
|
|
699
|
+
bool had_failures = suite_end(suite_failures);
|
|
700
|
+
print_suite_title("Callouts Tests", had_failures, false);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Test blockquotes with lists
|
|
705
|
+
*/
|
|
706
|
+
|
|
707
|
+
void test_blockquote_lists(void) {
|
|
708
|
+
int suite_failures = suite_start();
|
|
709
|
+
print_suite_title("Blockquote Lists Tests", false, true);
|
|
710
|
+
|
|
711
|
+
apex_options opts = apex_options_default();
|
|
712
|
+
char *html;
|
|
713
|
+
|
|
714
|
+
/* Test unordered list in blockquote */
|
|
715
|
+
html = apex_markdown_to_html("> Quote text\n>\n> - Item 1\n> - Item 2\n> - Item 3", 50, &opts);
|
|
716
|
+
assert_contains(html, "<blockquote>", "Blockquote with list has blockquote tag");
|
|
717
|
+
assert_contains(html, "<ul>", "Blockquote contains unordered list");
|
|
718
|
+
assert_contains(html, "<li>Item 1</li>", "First list item in blockquote");
|
|
719
|
+
assert_contains(html, "<li>Item 2</li>", "Second list item in blockquote");
|
|
720
|
+
assert_contains(html, "<li>Item 3</li>", "Third list item in blockquote");
|
|
721
|
+
apex_free_string(html);
|
|
722
|
+
|
|
723
|
+
/* Test ordered list in blockquote */
|
|
724
|
+
const char *ordered_list = "> Numbered items:\n>\n> 1. First\n> 2. Second\n> 3. Third";
|
|
725
|
+
html = apex_markdown_to_html(ordered_list, strlen(ordered_list), &opts);
|
|
726
|
+
assert_contains(html, "<blockquote>", "Blockquote with ordered list");
|
|
727
|
+
assert_contains(html, "<ol>", "Blockquote contains ordered list");
|
|
728
|
+
assert_contains(html, "<li>First</li>", "First ordered item");
|
|
729
|
+
assert_contains(html, "<li>Second</li>", "Second ordered item");
|
|
730
|
+
assert_contains(html, "<li>Third</li>", "Third ordered item");
|
|
731
|
+
apex_free_string(html);
|
|
732
|
+
|
|
733
|
+
/* Test nested list in blockquote */
|
|
734
|
+
html = apex_markdown_to_html("> Main list:\n>\n> - Item 1\n> - Nested 1\n> - Nested 2\n> - Item 2", 60, &opts);
|
|
735
|
+
assert_contains(html, "<blockquote>", "Blockquote with nested list");
|
|
736
|
+
assert_contains(html, "<ul>", "Outer list present");
|
|
737
|
+
assert_contains(html, "<li>Item 1", "Outer list item");
|
|
738
|
+
assert_contains(html, "<li>Nested 1", "Nested list item");
|
|
739
|
+
assert_contains(html, "<li>Nested 2", "Second nested item");
|
|
740
|
+
apex_free_string(html);
|
|
741
|
+
|
|
742
|
+
/* Test list with paragraph in blockquote */
|
|
743
|
+
const char *list_para = "> Introduction\n>\n> - Point one\n> - Point two\n>\n> Conclusion";
|
|
744
|
+
html = apex_markdown_to_html(list_para, strlen(list_para), &opts);
|
|
745
|
+
assert_contains(html, "<blockquote>", "Blockquote with list and paragraphs");
|
|
746
|
+
assert_contains(html, "Introduction", "Paragraph before list");
|
|
747
|
+
assert_contains(html, "<ul>", "List present");
|
|
748
|
+
/* Conclusion may be in a separate blockquote or paragraph */
|
|
749
|
+
assert_contains(html, "Conclusion", "Conclusion text present");
|
|
750
|
+
apex_free_string(html);
|
|
751
|
+
|
|
752
|
+
/* Test task list in blockquote (requires GFM mode) */
|
|
753
|
+
apex_options gfm_opts = apex_options_for_mode(APEX_MODE_GFM);
|
|
754
|
+
const char *task_list = "> Tasks:\n>\n> - [ ] Todo\n> - [x] Done\n> - [ ] Another";
|
|
755
|
+
html = apex_markdown_to_html(task_list, strlen(task_list), &gfm_opts);
|
|
756
|
+
assert_contains(html, "<blockquote>", "Blockquote with task list");
|
|
757
|
+
/* Task lists in blockquotes may not render checkboxes - verify content is present */
|
|
758
|
+
assert_contains(html, "Todo", "Todo item");
|
|
759
|
+
assert_contains(html, "Done", "Done item");
|
|
760
|
+
apex_free_string(html);
|
|
761
|
+
|
|
762
|
+
/* Test definition list in blockquote (MMD mode) */
|
|
763
|
+
html = apex_markdown_to_html("> Terms:\n>\n> Term 1\n> : Definition 1\n>\n> Term 2\n> : Definition 2", 60, &opts);
|
|
764
|
+
assert_contains(html, "<blockquote>", "Blockquote with definition list");
|
|
765
|
+
/* Definition lists may or may not be parsed depending on mode */
|
|
766
|
+
apex_free_string(html);
|
|
767
|
+
|
|
768
|
+
bool had_failures = suite_end(suite_failures);
|
|
769
|
+
print_suite_title("Blockquote Lists Tests", had_failures, false);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Test TOC generation
|
|
774
|
+
*/
|
|
775
|
+
|
|
776
|
+
void test_html_markdown_attributes(void) {
|
|
777
|
+
int suite_failures = suite_start();
|
|
778
|
+
print_suite_title("HTML Markdown Attributes Tests", false, true);
|
|
779
|
+
|
|
780
|
+
apex_options opts = apex_options_default();
|
|
781
|
+
char *html;
|
|
782
|
+
|
|
783
|
+
/* Test markdown="1" (parse as block markdown) */
|
|
784
|
+
const char *block1 = "<div markdown=\"1\">\n# Header\n\n**bold**\n</div>";
|
|
785
|
+
html = apex_markdown_to_html(block1, strlen(block1), &opts);
|
|
786
|
+
assert_contains(html, "<h1>Header</h1>", "markdown=\"1\" parses headers");
|
|
787
|
+
assert_contains(html, "<strong>bold</strong>", "markdown=\"1\" parses emphasis");
|
|
788
|
+
apex_free_string(html);
|
|
789
|
+
|
|
790
|
+
/* Test markdown="block" (parse as block markdown) */
|
|
791
|
+
const char *block_attr = "<div markdown=\"block\">\n## Section\n\n- List item\n</div>";
|
|
792
|
+
html = apex_markdown_to_html(block_attr, strlen(block_attr), &opts);
|
|
793
|
+
assert_contains(html, "<h2>Section</h2>", "markdown=\"block\" parses headers");
|
|
794
|
+
assert_contains(html, "<li>List item</li>", "markdown=\"block\" parses lists");
|
|
795
|
+
apex_free_string(html);
|
|
796
|
+
|
|
797
|
+
/* Test markdown="span" (parse as inline markdown) */
|
|
798
|
+
const char *span = "<div markdown=\"span\">**bold** and *italic*</div>";
|
|
799
|
+
html = apex_markdown_to_html(span, strlen(span), &opts);
|
|
800
|
+
assert_contains(html, "<strong>bold</strong>", "markdown=\"span\" parses bold");
|
|
801
|
+
assert_contains(html, "<em>italic</em>", "markdown=\"span\" parses italic");
|
|
802
|
+
apex_free_string(html);
|
|
803
|
+
|
|
804
|
+
/* Test markdown="0" (no processing) */
|
|
805
|
+
const char *no_parse = "<div markdown=\"0\">\n**not bold**\n</div>";
|
|
806
|
+
html = apex_markdown_to_html(no_parse, strlen(no_parse), &opts);
|
|
807
|
+
assert_contains(html, "**not bold**", "markdown=\"0\" preserves literal text");
|
|
808
|
+
apex_free_string(html);
|
|
809
|
+
|
|
810
|
+
/* Test nested HTML with markdown - nested tags may not parse */
|
|
811
|
+
const char *nested = "<section markdown=\"1\">\n<div>\n# Nested Header\n</div>\n</section>";
|
|
812
|
+
html = apex_markdown_to_html(nested, strlen(nested), &opts);
|
|
813
|
+
// Note: Nested HTML processing may need refinement
|
|
814
|
+
assert_contains(html, "<section>", "Section tag preserved");
|
|
815
|
+
// assert_contains(html, "<h1>", "Nested HTML with markdown");
|
|
816
|
+
apex_free_string(html);
|
|
817
|
+
|
|
818
|
+
/* Test HTML without markdown attribute (default behavior) */
|
|
819
|
+
const char *no_attr = "<div>\n**should not parse**\n</div>";
|
|
820
|
+
html = apex_markdown_to_html(no_attr, strlen(no_attr), &opts);
|
|
821
|
+
// Without markdown attribute, HTML content is typically preserved
|
|
822
|
+
assert_contains(html, "<div>", "HTML preserved without markdown attribute");
|
|
823
|
+
apex_free_string(html);
|
|
824
|
+
|
|
825
|
+
bool had_failures = suite_end(suite_failures);
|
|
826
|
+
print_suite_title("HTML Markdown Attributes Tests", had_failures, false);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Test Pandoc fenced divs
|
|
831
|
+
*/
|
|
832
|
+
|
|
833
|
+
void test_fenced_divs(void) {
|
|
834
|
+
int suite_failures = suite_start();
|
|
835
|
+
print_suite_title("Fenced Divs Tests", false, true);
|
|
836
|
+
|
|
837
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
838
|
+
opts.enable_divs = true;
|
|
839
|
+
char *html;
|
|
840
|
+
|
|
841
|
+
/* Test basic fenced div with ID and class */
|
|
842
|
+
const char *basic_div = "::::: {#special .sidebar}\nHere is a paragraph.\n\nAnd another.\n:::::";
|
|
843
|
+
html = apex_markdown_to_html(basic_div, strlen(basic_div), &opts);
|
|
844
|
+
assert_contains(html, "<div", "Basic fenced div renders");
|
|
845
|
+
assert_contains(html, "id=\"special\"", "Fenced div has ID");
|
|
846
|
+
assert_contains(html, "class=\"sidebar\"", "Fenced div has class");
|
|
847
|
+
assert_contains(html, "Here is a paragraph", "Fenced div content preserved");
|
|
848
|
+
assert_contains(html, "</div>", "Fenced div properly closed");
|
|
849
|
+
apex_free_string(html);
|
|
850
|
+
|
|
851
|
+
/* Test fenced div with single unbraced word (treated as class) */
|
|
852
|
+
const char *unbraced_class = "::: sidebar\nThis is a div.\n:::";
|
|
853
|
+
html = apex_markdown_to_html(unbraced_class, strlen(unbraced_class), &opts);
|
|
854
|
+
assert_contains(html, "<div", "Unbraced class div renders");
|
|
855
|
+
assert_contains(html, "class=\"sidebar\"", "Unbraced word becomes class");
|
|
856
|
+
apex_free_string(html);
|
|
857
|
+
|
|
858
|
+
/* Test fenced div with multiple classes */
|
|
859
|
+
const char *multiple_classes = "::::: {.warning .important .highlight}\nWarning text\n:::::";
|
|
860
|
+
html = apex_markdown_to_html(multiple_classes, strlen(multiple_classes), &opts);
|
|
861
|
+
assert_contains(html, "<div", "Multiple classes div renders");
|
|
862
|
+
assert_contains(html, "class=\"warning important highlight\"", "Multiple classes applied");
|
|
863
|
+
apex_free_string(html);
|
|
864
|
+
|
|
865
|
+
/* Test fenced div with custom attributes */
|
|
866
|
+
const char *custom_attrs = "::::: {#mydiv .container key=\"value\" data-id=\"123\"}\nContent\n:::::";
|
|
867
|
+
html = apex_markdown_to_html(custom_attrs, strlen(custom_attrs), &opts);
|
|
868
|
+
assert_contains(html, "<div", "Custom attributes div renders");
|
|
869
|
+
assert_contains(html, "id=\"mydiv\"", "Custom attributes div has ID");
|
|
870
|
+
assert_contains(html, "class=\"container\"", "Custom attributes div has class");
|
|
871
|
+
assert_contains(html, "key=\"value\"", "Custom attribute key present");
|
|
872
|
+
assert_contains(html, "data-id=\"123\"", "Custom attribute data-id present");
|
|
873
|
+
apex_free_string(html);
|
|
874
|
+
|
|
875
|
+
/* Test fenced div with trailing colons */
|
|
876
|
+
const char *trailing_colons = "::::: {#special .sidebar} ::::\nContent\n::::::::::::::::::";
|
|
877
|
+
html = apex_markdown_to_html(trailing_colons, strlen(trailing_colons), &opts);
|
|
878
|
+
assert_contains(html, "<div", "Trailing colons div renders");
|
|
879
|
+
assert_contains(html, "id=\"special\"", "Trailing colons div has ID");
|
|
880
|
+
apex_free_string(html);
|
|
881
|
+
|
|
882
|
+
/* Test nested fenced divs */
|
|
883
|
+
const char *nested_divs = "::: Warning ::::::\nOuter warning.\n\n::: Danger\nInner danger.\n:::\n::::::::::::::::::";
|
|
884
|
+
html = apex_markdown_to_html(nested_divs, strlen(nested_divs), &opts);
|
|
885
|
+
assert_contains(html, "<div", "Nested divs render");
|
|
886
|
+
assert_contains(html, "class=\"Warning\"", "Outer div class");
|
|
887
|
+
assert_contains(html, "class=\"Danger\"", "Inner div class");
|
|
888
|
+
assert_contains(html, "Outer warning", "Outer div content");
|
|
889
|
+
assert_contains(html, "Inner danger", "Inner div content");
|
|
890
|
+
/* Should have two opening divs and two closing divs */
|
|
891
|
+
size_t open_count = 0, close_count = 0;
|
|
892
|
+
const char *p = html;
|
|
893
|
+
while ((p = strstr(p, "<div")) != NULL) {
|
|
894
|
+
open_count++;
|
|
895
|
+
p += 4;
|
|
896
|
+
}
|
|
897
|
+
p = html;
|
|
898
|
+
while ((p = strstr(p, "</div>")) != NULL) {
|
|
899
|
+
close_count++;
|
|
900
|
+
p += 6;
|
|
901
|
+
}
|
|
902
|
+
if (open_count >= 2 && close_count >= 2) {
|
|
903
|
+
tests_run++;
|
|
904
|
+
tests_passed++;
|
|
905
|
+
if (!errors_only_output) {
|
|
906
|
+
printf(COLOR_GREEN "✓" COLOR_RESET " Nested divs properly structured\n");
|
|
907
|
+
}
|
|
908
|
+
} else {
|
|
909
|
+
tests_run++;
|
|
910
|
+
tests_failed++;
|
|
911
|
+
printf(COLOR_RED "✗" COLOR_RESET " Nested divs properly structured\n");
|
|
912
|
+
}
|
|
913
|
+
apex_free_string(html);
|
|
914
|
+
|
|
915
|
+
/* Test fenced div with block type (aside) */
|
|
916
|
+
const char *aside_block = "::: >aside {.sidebar}\nThis is an aside block.\n:::";
|
|
917
|
+
html = apex_markdown_to_html(aside_block, strlen(aside_block), &opts);
|
|
918
|
+
assert_contains(html, "<aside", "Aside block renders");
|
|
919
|
+
assert_contains(html, "</aside>", "Aside block closes");
|
|
920
|
+
assert_contains(html, "class=\"sidebar\"", "Aside block has class");
|
|
921
|
+
assert_contains(html, "This is an aside block", "Aside block content");
|
|
922
|
+
apex_free_string(html);
|
|
923
|
+
|
|
924
|
+
/* Test fenced div with block type (article) */
|
|
925
|
+
const char *article_block = "::: >article {#post .main}\nArticle content here.\n:::";
|
|
926
|
+
html = apex_markdown_to_html(article_block, strlen(article_block), &opts);
|
|
927
|
+
assert_contains(html, "<article", "Article block renders");
|
|
928
|
+
assert_contains(html, "</article>", "Article block closes");
|
|
929
|
+
assert_contains(html, "id=\"post\"", "Article block has ID");
|
|
930
|
+
assert_contains(html, "class=\"main\"", "Article block has class");
|
|
931
|
+
apex_free_string(html);
|
|
932
|
+
|
|
933
|
+
/* Test fenced div with block type (details/summary - nested) */
|
|
934
|
+
const char *details_block = "::: >details {.warning} :::\n:::: >summary\nThis is a summary\n::::\nThis is the content of the details block\n:::";
|
|
935
|
+
html = apex_markdown_to_html(details_block, strlen(details_block), &opts);
|
|
936
|
+
assert_contains(html, "<details", "Details block renders");
|
|
937
|
+
assert_contains(html, "</details>", "Details block closes");
|
|
938
|
+
assert_contains(html, "<summary", "Summary block renders");
|
|
939
|
+
assert_contains(html, "</summary>", "Summary block closes");
|
|
940
|
+
assert_contains(html, "class=\"warning\"", "Details block has class");
|
|
941
|
+
assert_contains(html, "This is a summary", "Summary content");
|
|
942
|
+
assert_contains(html, "This is the content of the details block", "Details content");
|
|
943
|
+
apex_free_string(html);
|
|
944
|
+
|
|
945
|
+
/* Test fenced div with block type and unbraced class */
|
|
946
|
+
const char *aside_unbraced = "::: >aside Warning :::\nWarning content.\n:::";
|
|
947
|
+
html = apex_markdown_to_html(aside_unbraced, strlen(aside_unbraced), &opts);
|
|
948
|
+
assert_contains(html, "<aside", "Aside with unbraced class renders");
|
|
949
|
+
assert_contains(html, "class=\"Warning\"", "Aside has unbraced class");
|
|
950
|
+
apex_free_string(html);
|
|
951
|
+
|
|
952
|
+
/* Test default div behavior (no > prefix) */
|
|
953
|
+
const char *default_div = "::: {.container}\nRegular div content.\n:::";
|
|
954
|
+
html = apex_markdown_to_html(default_div, strlen(default_div), &opts);
|
|
955
|
+
assert_contains(html, "<div", "Default div renders");
|
|
956
|
+
assert_contains(html, "</div>", "Default div closes");
|
|
957
|
+
assert_contains(html, "class=\"container\"", "Default div has class");
|
|
958
|
+
apex_free_string(html);
|
|
959
|
+
|
|
960
|
+
/* Test nested blocks with different types */
|
|
961
|
+
const char *nested_blocks = "::: >section {.outer} :::\nOuter section.\n\n::: >aside {.inner}\nInner aside.\n:::\n\nMore outer content.\n:::";
|
|
962
|
+
html = apex_markdown_to_html(nested_blocks, strlen(nested_blocks), &opts);
|
|
963
|
+
assert_contains(html, "<section", "Nested section renders");
|
|
964
|
+
assert_contains(html, "</section>", "Nested section closes");
|
|
965
|
+
assert_contains(html, "<aside", "Nested aside renders");
|
|
966
|
+
assert_contains(html, "</aside>", "Nested aside closes");
|
|
967
|
+
assert_contains(html, "Outer section", "Outer content");
|
|
968
|
+
assert_contains(html, "Inner aside", "Inner content");
|
|
969
|
+
apex_free_string(html);
|
|
970
|
+
|
|
971
|
+
/* Test block type with section */
|
|
972
|
+
const char *section_block = "::: >section {#chapter1 .main-section}\nSection content here.\n:::";
|
|
973
|
+
html = apex_markdown_to_html(section_block, strlen(section_block), &opts);
|
|
974
|
+
assert_contains(html, "<section", "Section block renders");
|
|
975
|
+
assert_contains(html, "</section>", "Section block closes");
|
|
976
|
+
assert_contains(html, "id=\"chapter1\"", "Section block has ID");
|
|
977
|
+
assert_contains(html, "class=\"main-section\"", "Section block has class");
|
|
978
|
+
apex_free_string(html);
|
|
979
|
+
|
|
980
|
+
/* Test block type with header */
|
|
981
|
+
const char *header_block = "::: >header {.site-header}\nSite header content\n:::";
|
|
982
|
+
html = apex_markdown_to_html(header_block, strlen(header_block), &opts);
|
|
983
|
+
assert_contains(html, "<header", "Header block renders");
|
|
984
|
+
assert_contains(html, "</header>", "Header block closes");
|
|
985
|
+
apex_free_string(html);
|
|
986
|
+
|
|
987
|
+
/* Test block type with footer */
|
|
988
|
+
const char *footer_block = "::: >footer {.site-footer}\nSite footer content\n:::";
|
|
989
|
+
html = apex_markdown_to_html(footer_block, strlen(footer_block), &opts);
|
|
990
|
+
assert_contains(html, "<footer", "Footer block renders");
|
|
991
|
+
assert_contains(html, "</footer>", "Footer block closes");
|
|
992
|
+
apex_free_string(html);
|
|
993
|
+
|
|
994
|
+
/* Test block type with nav */
|
|
995
|
+
const char *nav_block = "::: >nav {.main-nav}\nNavigation content\n:::";
|
|
996
|
+
html = apex_markdown_to_html(nav_block, strlen(nav_block), &opts);
|
|
997
|
+
assert_contains(html, "<nav", "Nav block renders");
|
|
998
|
+
assert_contains(html, "</nav>", "Nav block closes");
|
|
999
|
+
apex_free_string(html);
|
|
1000
|
+
|
|
1001
|
+
/* Test block type with explicit div */
|
|
1002
|
+
const char *explicit_div = "::: >div {.custom-div}\nExplicit div content\n:::";
|
|
1003
|
+
html = apex_markdown_to_html(explicit_div, strlen(explicit_div), &opts);
|
|
1004
|
+
assert_contains(html, "<div", "Explicit div block renders");
|
|
1005
|
+
assert_contains(html, "</div>", "Explicit div block closes");
|
|
1006
|
+
apex_free_string(html);
|
|
1007
|
+
|
|
1008
|
+
/* Test block type with trailing colons */
|
|
1009
|
+
const char *block_trailing = "::: >aside {.sidebar} :::\nContent with trailing colons\n:::";
|
|
1010
|
+
html = apex_markdown_to_html(block_trailing, strlen(block_trailing), &opts);
|
|
1011
|
+
assert_contains(html, "<aside", "Block with trailing colons renders");
|
|
1012
|
+
assert_contains(html, "class=\"sidebar\"", "Block with trailing colons has class");
|
|
1013
|
+
apex_free_string(html);
|
|
1014
|
+
|
|
1015
|
+
/* Test block type with multiple attributes */
|
|
1016
|
+
const char *block_multi_attr = "::: >article {#post .main .highlight data-id=\"123\" role=\"main\"}\nArticle with multiple attributes\n:::";
|
|
1017
|
+
html = apex_markdown_to_html(block_multi_attr, strlen(block_multi_attr), &opts);
|
|
1018
|
+
assert_contains(html, "<article", "Block with multiple attributes renders");
|
|
1019
|
+
assert_contains(html, "id=\"post\"", "Block has ID");
|
|
1020
|
+
assert_contains(html, "class=\"main highlight\"", "Block has multiple classes");
|
|
1021
|
+
assert_contains(html, "data-id=\"123\"", "Block has data attribute");
|
|
1022
|
+
assert_contains(html, "role=\"main\"", "Block has role attribute");
|
|
1023
|
+
apex_free_string(html);
|
|
1024
|
+
|
|
1025
|
+
/* Test deeply nested block types */
|
|
1026
|
+
const char *deep_nested = "::: >section {.level1} :::\nLevel 1\n\n::: >article {.level2}\nLevel 2\n\n::: >aside {.level3}\nLevel 3\n:::\n\nMore level 2\n:::\n\nMore level 1\n:::";
|
|
1027
|
+
html = apex_markdown_to_html(deep_nested, strlen(deep_nested), &opts);
|
|
1028
|
+
assert_contains(html, "<section", "Deep nested section renders");
|
|
1029
|
+
assert_contains(html, "</section>", "Deep nested section closes");
|
|
1030
|
+
assert_contains(html, "<article", "Deep nested article renders");
|
|
1031
|
+
assert_contains(html, "</article>", "Deep nested article closes");
|
|
1032
|
+
assert_contains(html, "<aside", "Deep nested aside renders");
|
|
1033
|
+
assert_contains(html, "</aside>", "Deep nested aside closes");
|
|
1034
|
+
assert_contains(html, "Level 1", "Deep nested level 1 content");
|
|
1035
|
+
assert_contains(html, "Level 2", "Deep nested level 2 content");
|
|
1036
|
+
assert_contains(html, "Level 3", "Deep nested level 3 content");
|
|
1037
|
+
apex_free_string(html);
|
|
1038
|
+
|
|
1039
|
+
/* Test mixed block types and regular divs */
|
|
1040
|
+
const char *mixed_types = "::: >section {.outer}\nSection content\n\n::: {.regular-div}\nRegular div inside section\n:::\n\n::: >aside {.aside-in-section}\nAside inside section\n:::\n\nMore section content\n:::";
|
|
1041
|
+
html = apex_markdown_to_html(mixed_types, strlen(mixed_types), &opts);
|
|
1042
|
+
assert_contains(html, "<section", "Mixed types section renders");
|
|
1043
|
+
assert_contains(html, "</section>", "Mixed types section closes");
|
|
1044
|
+
assert_contains(html, "<div", "Mixed types regular div renders");
|
|
1045
|
+
assert_contains(html, "</div>", "Mixed types regular div closes");
|
|
1046
|
+
assert_contains(html, "<aside", "Mixed types aside renders");
|
|
1047
|
+
assert_contains(html, "</aside>", "Mixed types aside closes");
|
|
1048
|
+
apex_free_string(html);
|
|
1049
|
+
|
|
1050
|
+
/* Test block type with hyphenated name */
|
|
1051
|
+
const char *hyphenated = "::: >custom-element {.test}\nCustom element content\n:::";
|
|
1052
|
+
html = apex_markdown_to_html(hyphenated, strlen(hyphenated), &opts);
|
|
1053
|
+
assert_contains(html, "<custom-element", "Hyphenated block type renders");
|
|
1054
|
+
assert_contains(html, "</custom-element>", "Hyphenated block type closes");
|
|
1055
|
+
apex_free_string(html);
|
|
1056
|
+
|
|
1057
|
+
/* Test block type preserves markdown parsing */
|
|
1058
|
+
const char *block_with_markdown = "::: >article {.content}\n## Heading\n\nParagraph with **bold** text.\n:::";
|
|
1059
|
+
html = apex_markdown_to_html(block_with_markdown, strlen(block_with_markdown), &opts);
|
|
1060
|
+
assert_contains(html, "<article", "Block with markdown renders");
|
|
1061
|
+
assert_contains(html, "<h2", "Block content parsed as markdown (heading)");
|
|
1062
|
+
assert_contains(html, "Heading", "Block content parsed as markdown (heading text)");
|
|
1063
|
+
assert_contains(html, "<strong", "Block content parsed as markdown (bold)");
|
|
1064
|
+
assert_contains(html, "bold", "Block content parsed as markdown (bold text)");
|
|
1065
|
+
apex_free_string(html);
|
|
1066
|
+
|
|
1067
|
+
/* Test minimum 3 colons */
|
|
1068
|
+
const char *min_colons = "::: {.minimal}\nMinimal div\n:::";
|
|
1069
|
+
html = apex_markdown_to_html(min_colons, strlen(min_colons), &opts);
|
|
1070
|
+
assert_contains(html, "<div", "Minimum colons div renders");
|
|
1071
|
+
assert_contains(html, "class=\"minimal\"", "Minimum colons div has class");
|
|
1072
|
+
apex_free_string(html);
|
|
1073
|
+
|
|
1074
|
+
/* Test fenced div with only ID */
|
|
1075
|
+
const char *only_id = "::: {#only-id}\nDiv with only ID\n:::";
|
|
1076
|
+
html = apex_markdown_to_html(only_id, strlen(only_id), &opts);
|
|
1077
|
+
assert_contains(html, "<div", "Only ID div renders");
|
|
1078
|
+
assert_contains(html, "id=\"only-id\"", "Only ID div has ID");
|
|
1079
|
+
assert_not_contains(html, "class=", "Only ID div has no class");
|
|
1080
|
+
apex_free_string(html);
|
|
1081
|
+
|
|
1082
|
+
/* Test fenced div with only classes */
|
|
1083
|
+
const char *only_classes = "::: {.only-classes .multiple}\nDiv with only classes\n:::";
|
|
1084
|
+
html = apex_markdown_to_html(only_classes, strlen(only_classes), &opts);
|
|
1085
|
+
assert_contains(html, "<div", "Only classes div renders");
|
|
1086
|
+
assert_contains(html, "class=\"only-classes multiple\"", "Only classes div has classes");
|
|
1087
|
+
assert_not_contains(html, "id=", "Only classes div has no ID");
|
|
1088
|
+
apex_free_string(html);
|
|
1089
|
+
|
|
1090
|
+
/* Test fenced div with quoted attribute values */
|
|
1091
|
+
const char *quoted_values = "::::: {#quoted .test attr1=\"quoted value\" attr2='single quoted'}\nContent\n:::::";
|
|
1092
|
+
html = apex_markdown_to_html(quoted_values, strlen(quoted_values), &opts);
|
|
1093
|
+
assert_contains(html, "<div", "Quoted values div renders");
|
|
1094
|
+
assert_contains(html, "attr1=\"quoted value\"", "Double-quoted attribute");
|
|
1095
|
+
assert_contains(html, "attr2=\"single quoted\"", "Single-quoted attribute converted");
|
|
1096
|
+
apex_free_string(html);
|
|
1097
|
+
|
|
1098
|
+
/* Test fenced div disabled in non-Unified mode */
|
|
1099
|
+
apex_options gfm_opts = apex_options_for_mode(APEX_MODE_GFM);
|
|
1100
|
+
gfm_opts.enable_divs = true; /* Even if enabled, should not work in GFM mode */
|
|
1101
|
+
const char *div_in_gfm = "::: {.test}\nContent\n:::";
|
|
1102
|
+
html = apex_markdown_to_html(div_in_gfm, strlen(div_in_gfm), &gfm_opts);
|
|
1103
|
+
assert_not_contains(html, "<div", "Fenced divs disabled in GFM mode");
|
|
1104
|
+
apex_free_string(html);
|
|
1105
|
+
|
|
1106
|
+
/* Test fenced div disabled with --no-divs flag */
|
|
1107
|
+
apex_options no_divs_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
1108
|
+
no_divs_opts.enable_divs = false;
|
|
1109
|
+
const char *div_disabled = "::: {.test}\nContent\n:::";
|
|
1110
|
+
html = apex_markdown_to_html(div_disabled, strlen(div_disabled), &no_divs_opts);
|
|
1111
|
+
assert_not_contains(html, "<div", "Fenced divs disabled with --no-divs");
|
|
1112
|
+
apex_free_string(html);
|
|
1113
|
+
|
|
1114
|
+
/* Test fenced div with mixed content (lists, blockquotes) */
|
|
1115
|
+
const char *mixed_content = "::::: {#mixed .content}\n- List item\n- Another item\n\n> A blockquote\n\nAnd a paragraph.\n:::::";
|
|
1116
|
+
html = apex_markdown_to_html(mixed_content, strlen(mixed_content), &opts);
|
|
1117
|
+
assert_contains(html, "<div", "Mixed content div renders");
|
|
1118
|
+
assert_contains(html, "<ul>", "Mixed content has list");
|
|
1119
|
+
assert_contains(html, "<blockquote>", "Mixed content has blockquote");
|
|
1120
|
+
assert_contains(html, "<p>And a paragraph.</p>", "Mixed content has paragraph");
|
|
1121
|
+
apex_free_string(html);
|
|
1122
|
+
|
|
1123
|
+
/* Test multiple fenced divs in sequence */
|
|
1124
|
+
const char *multiple_divs = "::: {.first}\nFirst div.\n:::\n\n::: {.second}\nSecond div.\n:::\n\n::: {.third}\nThird div.\n:::";
|
|
1125
|
+
html = apex_markdown_to_html(multiple_divs, strlen(multiple_divs), &opts);
|
|
1126
|
+
assert_contains(html, "class=\"first\"", "First div class");
|
|
1127
|
+
assert_contains(html, "class=\"second\"", "Second div class");
|
|
1128
|
+
assert_contains(html, "class=\"third\"", "Third div class");
|
|
1129
|
+
assert_contains(html, "First div", "First div content");
|
|
1130
|
+
assert_contains(html, "Second div", "Second div content");
|
|
1131
|
+
assert_contains(html, "Third div", "Third div content");
|
|
1132
|
+
apex_free_string(html);
|
|
1133
|
+
|
|
1134
|
+
bool had_failures = suite_end(suite_failures);
|
|
1135
|
+
print_suite_title("Fenced Divs Tests", had_failures, false);
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
/**
|
|
1139
|
+
* Test abbreviations
|
|
1140
|
+
*/
|
|
1141
|
+
|
|
1142
|
+
void test_abbreviations(void) {
|
|
1143
|
+
int suite_failures = suite_start();
|
|
1144
|
+
print_suite_title("Abbreviations Tests", false, true);
|
|
1145
|
+
|
|
1146
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
1147
|
+
char *html;
|
|
1148
|
+
|
|
1149
|
+
/* Test basic abbreviation */
|
|
1150
|
+
const char *abbr_doc = "*[HTML]: Hypertext Markup Language\n\nHTML is great.";
|
|
1151
|
+
html = apex_markdown_to_html(abbr_doc, strlen(abbr_doc), &opts);
|
|
1152
|
+
assert_contains(html, "<abbr", "Abbreviation tag created");
|
|
1153
|
+
assert_contains(html, "Hypertext Markup Language", "Abbreviation title");
|
|
1154
|
+
apex_free_string(html);
|
|
1155
|
+
|
|
1156
|
+
/* Test multiple abbreviations */
|
|
1157
|
+
const char *multi_abbr = "*[CSS]: Cascading Style Sheets\n*[JS]: JavaScript\n\nCSS and JS are essential.";
|
|
1158
|
+
html = apex_markdown_to_html(multi_abbr, strlen(multi_abbr), &opts);
|
|
1159
|
+
assert_contains(html, "<abbr", "Abbreviation tags present");
|
|
1160
|
+
assert_contains(html, "Cascading Style Sheets", "First abbreviation");
|
|
1161
|
+
assert_contains(html, "JavaScript", "Second abbreviation");
|
|
1162
|
+
apex_free_string(html);
|
|
1163
|
+
|
|
1164
|
+
/* Test abbreviation with multiple occurrences */
|
|
1165
|
+
const char *multiple = "*[API]: Application Programming Interface\n\nThe API docs explain the API usage.";
|
|
1166
|
+
html = apex_markdown_to_html(multiple, strlen(multiple), &opts);
|
|
1167
|
+
assert_contains(html, "<abbr", "Multiple occurrences wrapped");
|
|
1168
|
+
assert_contains(html, "Application Programming Interface", "Abbreviation definition");
|
|
1169
|
+
apex_free_string(html);
|
|
1170
|
+
|
|
1171
|
+
/* Test text without abbreviations */
|
|
1172
|
+
const char *no_abbr = "Just plain text here.";
|
|
1173
|
+
html = apex_markdown_to_html(no_abbr, strlen(no_abbr), &opts);
|
|
1174
|
+
assert_contains(html, "plain text", "Non-abbreviation text preserved");
|
|
1175
|
+
apex_free_string(html);
|
|
1176
|
+
|
|
1177
|
+
/* Test MMD 6 reference abbreviation: [>abbr]: expansion */
|
|
1178
|
+
const char *mmd6_ref = "[>MMD]: MultiMarkdown\n\n[>MMD] is great.";
|
|
1179
|
+
html = apex_markdown_to_html(mmd6_ref, strlen(mmd6_ref), &opts);
|
|
1180
|
+
assert_contains(html, "<abbr", "MMD 6 reference abbr tag");
|
|
1181
|
+
assert_contains(html, "MultiMarkdown", "MMD 6 reference expansion");
|
|
1182
|
+
apex_free_string(html);
|
|
1183
|
+
|
|
1184
|
+
/* Test MMD 6 inline abbreviation: [>(abbr) expansion] */
|
|
1185
|
+
const char *mmd6_inline = "This is [>(MD) Markdown] syntax.";
|
|
1186
|
+
html = apex_markdown_to_html(mmd6_inline, strlen(mmd6_inline), &opts);
|
|
1187
|
+
assert_contains(html, "<abbr title=\"Markdown\">MD</abbr>", "MMD 6 inline abbr");
|
|
1188
|
+
apex_free_string(html);
|
|
1189
|
+
|
|
1190
|
+
/* Test multiple MMD 6 inline abbreviations */
|
|
1191
|
+
const char *mmd6_multi = "[>(HTML) Hypertext] and [>(CSS) Styles] work.";
|
|
1192
|
+
html = apex_markdown_to_html(mmd6_multi, strlen(mmd6_multi), &opts);
|
|
1193
|
+
assert_contains(html, "title=\"Hypertext\">HTML</abbr>", "First MMD 6 inline");
|
|
1194
|
+
assert_contains(html, "title=\"Styles\">CSS</abbr>", "Second MMD 6 inline");
|
|
1195
|
+
apex_free_string(html);
|
|
1196
|
+
|
|
1197
|
+
/* Test mixing old and new syntax */
|
|
1198
|
+
const char *mixed = "*[OLD]: Old Style\n[>NEW]: New Style\n\nOLD and [>NEW] work.";
|
|
1199
|
+
html = apex_markdown_to_html(mixed, strlen(mixed), &opts);
|
|
1200
|
+
assert_contains(html, "Old Style", "Old syntax in mixed");
|
|
1201
|
+
assert_contains(html, "New Style", "New syntax in mixed");
|
|
1202
|
+
apex_free_string(html);
|
|
1203
|
+
|
|
1204
|
+
bool had_failures = suite_end(suite_failures);
|
|
1205
|
+
print_suite_title("Abbreviations Tests", had_failures, false);
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
/**
|
|
1209
|
+
* Test MMD 6 features: multi-line setext headers and link/image titles with different quotes
|
|
1210
|
+
*/
|
|
1211
|
+
|
|
1212
|
+
void test_mmd6_features(void) {
|
|
1213
|
+
int suite_failures = suite_start();
|
|
1214
|
+
print_suite_title("MMD 6 Features Tests", false, true);
|
|
1215
|
+
|
|
1216
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
1217
|
+
char *html;
|
|
1218
|
+
|
|
1219
|
+
/* Test multi-line setext header (h1) */
|
|
1220
|
+
const char *multiline_h1 = "This is\na multi-line\nsetext header\n========";
|
|
1221
|
+
html = apex_markdown_to_html(multiline_h1, strlen(multiline_h1), &opts);
|
|
1222
|
+
assert_contains(html, "<h1", "Multi-line setext h1 tag");
|
|
1223
|
+
assert_contains(html, "This is", "Multi-line setext h1 contains first line");
|
|
1224
|
+
assert_contains(html, "a multi-line", "Multi-line setext h1 contains second line");
|
|
1225
|
+
assert_contains(html, "setext header</h1>", "Multi-line setext h1 contains last line");
|
|
1226
|
+
apex_free_string(html);
|
|
1227
|
+
|
|
1228
|
+
/* Test multi-line setext header (h2) */
|
|
1229
|
+
const char *multiline_h2 = "Another\nheader\nwith\nmultiple\nlines\n--------";
|
|
1230
|
+
html = apex_markdown_to_html(multiline_h2, strlen(multiline_h2), &opts);
|
|
1231
|
+
assert_contains(html, "<h2", "Multi-line setext h2 tag");
|
|
1232
|
+
assert_contains(html, "Another", "Multi-line setext h2 contains first line");
|
|
1233
|
+
assert_contains(html, "multiple", "Multi-line setext h2 contains middle line");
|
|
1234
|
+
assert_contains(html, "lines</h2>", "Multi-line setext h2 contains last line");
|
|
1235
|
+
apex_free_string(html);
|
|
1236
|
+
|
|
1237
|
+
/* Test link title with double quotes */
|
|
1238
|
+
const char *link_double = "[Link](https://example.com \"Double quote title\")";
|
|
1239
|
+
html = apex_markdown_to_html(link_double, strlen(link_double), &opts);
|
|
1240
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Link with double quote title has href");
|
|
1241
|
+
assert_contains(html, "title=\"Double quote title\"", "Link with double quote title");
|
|
1242
|
+
apex_free_string(html);
|
|
1243
|
+
|
|
1244
|
+
/* Test link title with single quotes */
|
|
1245
|
+
const char *link_single = "[Link](https://example.com 'Single quote title')";
|
|
1246
|
+
html = apex_markdown_to_html(link_single, strlen(link_single), &opts);
|
|
1247
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Link with single quote title has href");
|
|
1248
|
+
assert_contains(html, "title=\"Single quote title\"", "Link with single quote title");
|
|
1249
|
+
apex_free_string(html);
|
|
1250
|
+
|
|
1251
|
+
/* Test link title with parentheses */
|
|
1252
|
+
const char *link_paren = "[Link](https://example.com (Parentheses title))";
|
|
1253
|
+
html = apex_markdown_to_html(link_paren, strlen(link_paren), &opts);
|
|
1254
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Link with parentheses title has href");
|
|
1255
|
+
assert_contains(html, "title=\"Parentheses title\"", "Link with parentheses title");
|
|
1256
|
+
apex_free_string(html);
|
|
1257
|
+
|
|
1258
|
+
/* Test image title with double quotes */
|
|
1259
|
+
const char *img_double = "";
|
|
1260
|
+
html = apex_markdown_to_html(img_double, strlen(img_double), &opts);
|
|
1261
|
+
assert_contains(html, "<img src=\"image.png\"", "Image with double quote title has src");
|
|
1262
|
+
assert_contains(html, "title=\"Double quote title\"", "Image with double quote title");
|
|
1263
|
+
apex_free_string(html);
|
|
1264
|
+
|
|
1265
|
+
/* Test image title with single quotes */
|
|
1266
|
+
const char *img_single = "";
|
|
1267
|
+
html = apex_markdown_to_html(img_single, strlen(img_single), &opts);
|
|
1268
|
+
assert_contains(html, "<img src=\"image.png\"", "Image with single quote title has src");
|
|
1269
|
+
assert_contains(html, "title=\"Single quote title\"", "Image with single quote title");
|
|
1270
|
+
apex_free_string(html);
|
|
1271
|
+
|
|
1272
|
+
/* Test image title with parentheses */
|
|
1273
|
+
const char *img_paren = ")";
|
|
1274
|
+
html = apex_markdown_to_html(img_paren, strlen(img_paren), &opts);
|
|
1275
|
+
assert_contains(html, "<img src=\"image.png\"", "Image with parentheses title has src");
|
|
1276
|
+
assert_contains(html, "title=\"Parentheses title\"", "Image with parentheses title");
|
|
1277
|
+
apex_free_string(html);
|
|
1278
|
+
|
|
1279
|
+
/* Test reference link with double quote title */
|
|
1280
|
+
const char *ref_double = "[Ref][id]\n\n[id]: https://example.com \"Reference title\"";
|
|
1281
|
+
html = apex_markdown_to_html(ref_double, strlen(ref_double), &opts);
|
|
1282
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Reference link with double quote title has href");
|
|
1283
|
+
assert_contains(html, "title=\"Reference title\"", "Reference link with double quote title");
|
|
1284
|
+
apex_free_string(html);
|
|
1285
|
+
|
|
1286
|
+
/* Test reference link with single quote title */
|
|
1287
|
+
const char *ref_single = "[Ref][id]\n\n[id]: https://example.com 'Reference title'";
|
|
1288
|
+
html = apex_markdown_to_html(ref_single, strlen(ref_single), &opts);
|
|
1289
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Reference link with single quote title has href");
|
|
1290
|
+
assert_contains(html, "title=\"Reference title\"", "Reference link with single quote title");
|
|
1291
|
+
apex_free_string(html);
|
|
1292
|
+
|
|
1293
|
+
/* Test reference link with parentheses title */
|
|
1294
|
+
const char *ref_paren = "[Ref][id]\n\n[id]: https://example.com (Reference title)";
|
|
1295
|
+
html = apex_markdown_to_html(ref_paren, strlen(ref_paren), &opts);
|
|
1296
|
+
assert_contains(html, "<a href=\"https://example.com\"", "Reference link with parentheses title has href");
|
|
1297
|
+
assert_contains(html, "title=\"Reference title\"", "Reference link with parentheses title");
|
|
1298
|
+
apex_free_string(html);
|
|
1299
|
+
|
|
1300
|
+
/* Test in unified mode as well */
|
|
1301
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
1302
|
+
const char *unified_test = "Multi\nLine\nHeader\n========\n\n[Link](url 'Title')";
|
|
1303
|
+
html = apex_markdown_to_html(unified_test, strlen(unified_test), &unified_opts);
|
|
1304
|
+
assert_contains(html, "<h1", "Multi-line setext header works in unified mode");
|
|
1305
|
+
assert_contains(html, "Multi\nLine\nHeader</h1>", "Multi-line setext header content in unified mode");
|
|
1306
|
+
assert_contains(html, "title=\"Title\"", "Link title with single quotes works in unified mode");
|
|
1307
|
+
apex_free_string(html);
|
|
1308
|
+
|
|
1309
|
+
bool had_failures = suite_end(suite_failures);
|
|
1310
|
+
print_suite_title("MMD 6 Features Tests", had_failures, false);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* Test emoji support
|
|
1315
|
+
*/
|
|
1316
|
+
|
|
1317
|
+
void test_emoji(void) {
|
|
1318
|
+
int suite_failures = suite_start();
|
|
1319
|
+
print_suite_title("Emoji Tests", false, true);
|
|
1320
|
+
|
|
1321
|
+
apex_options opts = apex_options_default();
|
|
1322
|
+
opts.enable_marked_extensions = true;
|
|
1323
|
+
char *html;
|
|
1324
|
+
|
|
1325
|
+
/* Test basic emoji */
|
|
1326
|
+
html = apex_markdown_to_html("Hello :smile: world", 19, &opts);
|
|
1327
|
+
assert_contains(html, "😄", "Smile emoji converted");
|
|
1328
|
+
apex_free_string(html);
|
|
1329
|
+
|
|
1330
|
+
/* Test multiple emoji */
|
|
1331
|
+
html = apex_markdown_to_html(":thumbsup: :heart: :rocket:", 27, &opts);
|
|
1332
|
+
assert_contains(html, "👍", "Thumbs up emoji");
|
|
1333
|
+
assert_contains(html, "❤", "Heart emoji");
|
|
1334
|
+
assert_contains(html, "🚀", "Rocket emoji");
|
|
1335
|
+
apex_free_string(html);
|
|
1336
|
+
|
|
1337
|
+
/* Test emoji in text */
|
|
1338
|
+
html = apex_markdown_to_html("I :heart: coding!", 17, &opts);
|
|
1339
|
+
assert_contains(html, "❤", "Emoji in sentence");
|
|
1340
|
+
assert_contains(html, "coding", "Regular text preserved");
|
|
1341
|
+
apex_free_string(html);
|
|
1342
|
+
|
|
1343
|
+
/* Test unknown emoji (should be preserved) */
|
|
1344
|
+
html = apex_markdown_to_html(":notarealemojicode:", 19, &opts);
|
|
1345
|
+
assert_contains(html, ":notarealemojicode:", "Unknown emoji preserved");
|
|
1346
|
+
apex_free_string(html);
|
|
1347
|
+
|
|
1348
|
+
/* Test emoji variations */
|
|
1349
|
+
html = apex_markdown_to_html(":star: :warning: :+1:", 21, &opts);
|
|
1350
|
+
assert_contains(html, "⭐", "Star emoji");
|
|
1351
|
+
assert_contains(html, "⚠", "Warning emoji");
|
|
1352
|
+
assert_contains(html, "👍", "Plus one emoji");
|
|
1353
|
+
apex_free_string(html);
|
|
1354
|
+
|
|
1355
|
+
bool had_failures = suite_end(suite_failures);
|
|
1356
|
+
print_suite_title("Emoji Tests", had_failures, false);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
/**
|
|
1360
|
+
* Test special markers (page breaks, pauses, end-of-block)
|
|
1361
|
+
*/
|
|
1362
|
+
|
|
1363
|
+
void test_special_markers(void) {
|
|
1364
|
+
int suite_failures = suite_start();
|
|
1365
|
+
print_suite_title("Special Markers Tests", false, true);
|
|
1366
|
+
|
|
1367
|
+
apex_options opts = apex_options_default();
|
|
1368
|
+
opts.enable_marked_extensions = true;
|
|
1369
|
+
char *html;
|
|
1370
|
+
|
|
1371
|
+
/* Test page break HTML comment */
|
|
1372
|
+
html = apex_markdown_to_html("Before\n\n<!--BREAK-->\n\nAfter", 28, &opts);
|
|
1373
|
+
assert_contains(html, "page-break-after", "Page break marker");
|
|
1374
|
+
assert_contains(html, "Before", "Content before break");
|
|
1375
|
+
assert_contains(html, "After", "Content after break");
|
|
1376
|
+
apex_free_string(html);
|
|
1377
|
+
|
|
1378
|
+
/* Test Kramdown page break */
|
|
1379
|
+
html = apex_markdown_to_html("Page 1\n\n{::pagebreak /}\n\nPage 2", 32, &opts);
|
|
1380
|
+
assert_contains(html, "page-break-after", "Kramdown page break");
|
|
1381
|
+
assert_contains(html, "Page 2", "Content after pagebreak");
|
|
1382
|
+
apex_free_string(html);
|
|
1383
|
+
|
|
1384
|
+
/* Test autoscroll pause */
|
|
1385
|
+
html = apex_markdown_to_html("Text\n\n<!--PAUSE:5-->\n\nMore text", 31, &opts);
|
|
1386
|
+
assert_contains(html, "data-pause", "Pause marker");
|
|
1387
|
+
assert_contains(html, "data-pause=\"5\"", "Pause duration");
|
|
1388
|
+
assert_contains(html, "More text", "Content after pause");
|
|
1389
|
+
apex_free_string(html);
|
|
1390
|
+
|
|
1391
|
+
/* Test end-of-block marker */
|
|
1392
|
+
const char *eob = "- Item 1\n\n^\n\n- Item 2";
|
|
1393
|
+
html = apex_markdown_to_html(eob, strlen(eob), &opts);
|
|
1394
|
+
// End of block should separate lists
|
|
1395
|
+
assert_contains(html, "<ul>", "Lists created");
|
|
1396
|
+
apex_free_string(html);
|
|
1397
|
+
|
|
1398
|
+
/* Test empty HTML comment as block separator (CommonMark spec) */
|
|
1399
|
+
const char *html_comment_separator = "- foo\n- bar\n\n<!-- -->\n\n- baz\n- bim";
|
|
1400
|
+
html = apex_markdown_to_html(html_comment_separator, strlen(html_comment_separator), &opts);
|
|
1401
|
+
// Should create two separate lists, not one merged list
|
|
1402
|
+
const char *first_ul = strstr(html, "<ul>");
|
|
1403
|
+
const char *second_ul = first_ul ? strstr(first_ul + 1, "<ul>") : NULL;
|
|
1404
|
+
if (second_ul != NULL) {
|
|
1405
|
+
test_result(true, "Empty HTML comment separates lists");
|
|
1406
|
+
} else {
|
|
1407
|
+
test_result(false, "Empty HTML comment does not separate lists");
|
|
1408
|
+
}
|
|
1409
|
+
assert_contains(html, "<li>foo</li>", "First list contains foo");
|
|
1410
|
+
assert_contains(html, "<li>bar</li>", "First list contains bar");
|
|
1411
|
+
assert_contains(html, "<li>baz</li>", "Second list contains baz");
|
|
1412
|
+
assert_contains(html, "<li>bim</li>", "Second list contains bim");
|
|
1413
|
+
assert_contains(html, "<!-- -->", "Empty HTML comment preserved");
|
|
1414
|
+
apex_free_string(html);
|
|
1415
|
+
|
|
1416
|
+
/* Test multiple page breaks */
|
|
1417
|
+
const char *multi = "Section 1\n\n<!--BREAK-->\n\nSection 2\n\n<!--BREAK-->\n\nSection 3";
|
|
1418
|
+
html = apex_markdown_to_html(multi, strlen(multi), &opts);
|
|
1419
|
+
assert_contains(html, "page-break-after", "Multiple page breaks");
|
|
1420
|
+
assert_contains(html, "Section 1", "First section");
|
|
1421
|
+
assert_contains(html, "Section 3", "Last section");
|
|
1422
|
+
apex_free_string(html);
|
|
1423
|
+
|
|
1424
|
+
bool had_failures = suite_end(suite_failures);
|
|
1425
|
+
print_suite_title("Special Markers Tests", had_failures, false);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* Test inline tables from CSV/TSV
|
|
1430
|
+
*/
|
|
1431
|
+
|
|
1432
|
+
void test_advanced_footnotes(void) {
|
|
1433
|
+
int suite_failures = suite_start();
|
|
1434
|
+
print_suite_title("Advanced Footnotes Tests", false, true);
|
|
1435
|
+
|
|
1436
|
+
apex_options opts = apex_options_for_mode(APEX_MODE_KRAMDOWN);
|
|
1437
|
+
char *html;
|
|
1438
|
+
|
|
1439
|
+
/* Direct call: cover NULL-root early return */
|
|
1440
|
+
test_result(apex_process_advanced_footnotes(NULL, NULL) == NULL, "advanced footnotes: NULL root returns NULL");
|
|
1441
|
+
|
|
1442
|
+
/* Test basic footnote */
|
|
1443
|
+
const char *basic = "Text[^1]\n\n[^1]: Footnote text";
|
|
1444
|
+
html = apex_markdown_to_html(basic, strlen(basic), &opts);
|
|
1445
|
+
assert_contains(html, "footnote", "Footnote generated");
|
|
1446
|
+
apex_free_string(html);
|
|
1447
|
+
|
|
1448
|
+
/* Test Kramdown inline footnote: ^[text] */
|
|
1449
|
+
const char *kramdown_inline = "Text^[Kramdown inline footnote]";
|
|
1450
|
+
html = apex_markdown_to_html(kramdown_inline, strlen(kramdown_inline), &opts);
|
|
1451
|
+
assert_contains(html, "footnote", "Kramdown inline footnote");
|
|
1452
|
+
assert_contains(html, "Kramdown inline footnote", "Kramdown footnote content");
|
|
1453
|
+
apex_free_string(html);
|
|
1454
|
+
|
|
1455
|
+
/* Test MMD inline footnote: [^text with spaces] */
|
|
1456
|
+
apex_options mmd_opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
1457
|
+
const char *mmd_inline = "Text[^MMD inline footnote with spaces]";
|
|
1458
|
+
html = apex_markdown_to_html(mmd_inline, strlen(mmd_inline), &mmd_opts);
|
|
1459
|
+
assert_contains(html, "footnote", "MMD inline footnote");
|
|
1460
|
+
assert_contains(html, "MMD inline footnote with spaces", "MMD footnote content");
|
|
1461
|
+
apex_free_string(html);
|
|
1462
|
+
|
|
1463
|
+
/* Test regular reference (no spaces) still works */
|
|
1464
|
+
const char *reference = "Text[^ref]\n\n[^ref]: Definition";
|
|
1465
|
+
html = apex_markdown_to_html(reference, strlen(reference), &mmd_opts);
|
|
1466
|
+
assert_contains(html, "footnote", "Regular reference footnote");
|
|
1467
|
+
assert_contains(html, "Definition", "Reference footnote content");
|
|
1468
|
+
apex_free_string(html);
|
|
1469
|
+
|
|
1470
|
+
/* Test multiple inline footnotes */
|
|
1471
|
+
const char *multiple = "First^[one] and second^[two] footnotes";
|
|
1472
|
+
html = apex_markdown_to_html(multiple, strlen(multiple), &opts);
|
|
1473
|
+
assert_contains(html, "one", "First inline footnote");
|
|
1474
|
+
assert_contains(html, "two", "Second inline footnote");
|
|
1475
|
+
apex_free_string(html);
|
|
1476
|
+
|
|
1477
|
+
/* Test inline footnote with formatting */
|
|
1478
|
+
const char *formatted = "Text^[footnote with **bold**]";
|
|
1479
|
+
html = apex_markdown_to_html(formatted, strlen(formatted), &opts);
|
|
1480
|
+
assert_contains(html, "footnote", "Formatted inline footnote");
|
|
1481
|
+
/* Note: Markdown in inline footnotes handled by cmark-gfm */
|
|
1482
|
+
apex_free_string(html);
|
|
1483
|
+
|
|
1484
|
+
/* Test advanced footnote with multiple paragraphs, list, and fenced code (```).
|
|
1485
|
+
* This should exercise the reparse path for block-level content inside footnotes.
|
|
1486
|
+
*/
|
|
1487
|
+
const char *blocky =
|
|
1488
|
+
"Text[^a]\n"
|
|
1489
|
+
"\n"
|
|
1490
|
+
"[^a]: First para\n"
|
|
1491
|
+
"\n"
|
|
1492
|
+
" Second para\n"
|
|
1493
|
+
"\n"
|
|
1494
|
+
" - item1\n"
|
|
1495
|
+
" - item2\n"
|
|
1496
|
+
"\n"
|
|
1497
|
+
" ```\n"
|
|
1498
|
+
" code\n"
|
|
1499
|
+
" ```\n";
|
|
1500
|
+
html = apex_markdown_to_html(blocky, strlen(blocky), &opts);
|
|
1501
|
+
assert_contains(html, "<p>First para</p>", "Advanced footnote: first paragraph");
|
|
1502
|
+
assert_contains(html, "<p>Second para</p>", "Advanced footnote: second paragraph");
|
|
1503
|
+
assert_contains(html, "<ul>", "Advanced footnote: list parsed");
|
|
1504
|
+
assert_contains(html, "<li>item1</li>", "Advanced footnote: list item 1");
|
|
1505
|
+
assert_contains(html, "<pre><code>code", "Advanced footnote: fenced code block parsed");
|
|
1506
|
+
apex_free_string(html);
|
|
1507
|
+
|
|
1508
|
+
/* Test advanced footnote with indented code block (4+ spaces after newline). */
|
|
1509
|
+
const char *indented_code =
|
|
1510
|
+
"Text[^b]\n"
|
|
1511
|
+
"\n"
|
|
1512
|
+
"[^b]: Intro\n"
|
|
1513
|
+
"\n"
|
|
1514
|
+
" indented\n"
|
|
1515
|
+
" code\n";
|
|
1516
|
+
html = apex_markdown_to_html(indented_code, strlen(indented_code), &opts);
|
|
1517
|
+
assert_contains(html, "<p>Intro</p>", "Indented code footnote: intro paragraph");
|
|
1518
|
+
assert_contains(html, "<pre><code>indented", "Indented code footnote: code block parsed");
|
|
1519
|
+
apex_free_string(html);
|
|
1520
|
+
|
|
1521
|
+
/* Test advanced footnote with fenced code using ~~~ (alternate fence detection). */
|
|
1522
|
+
const char *tilde_fence =
|
|
1523
|
+
"Text[^c]\n"
|
|
1524
|
+
"\n"
|
|
1525
|
+
"[^c]: Para\n"
|
|
1526
|
+
"\n"
|
|
1527
|
+
" ~~~\n"
|
|
1528
|
+
" tilde\n"
|
|
1529
|
+
" ~~~\n";
|
|
1530
|
+
html = apex_markdown_to_html(tilde_fence, strlen(tilde_fence), &opts);
|
|
1531
|
+
assert_contains(html, "<pre><code>tilde", "Tilde fence footnote: code block parsed");
|
|
1532
|
+
apex_free_string(html);
|
|
1533
|
+
|
|
1534
|
+
/* Test ordered list inside footnote. */
|
|
1535
|
+
const char *ordered_list =
|
|
1536
|
+
"Text[^d]\n"
|
|
1537
|
+
"\n"
|
|
1538
|
+
"[^d]: Steps\n"
|
|
1539
|
+
"\n"
|
|
1540
|
+
" 1. one\n"
|
|
1541
|
+
" 2. two\n";
|
|
1542
|
+
html = apex_markdown_to_html(ordered_list, strlen(ordered_list), &opts);
|
|
1543
|
+
assert_contains(html, "<p>Steps</p>", "Ordered list footnote: intro paragraph");
|
|
1544
|
+
assert_contains(html, "<ol>", "Ordered list footnote: ordered list parsed");
|
|
1545
|
+
assert_contains(html, "<li>one</li>", "Ordered list footnote: first item");
|
|
1546
|
+
assert_contains(html, "<li>two</li>", "Ordered list footnote: second item");
|
|
1547
|
+
apex_free_string(html);
|
|
1548
|
+
|
|
1549
|
+
bool had_failures = suite_end(suite_failures);
|
|
1550
|
+
print_suite_title("Advanced Footnotes Tests", had_failures, false);
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/**
|
|
1554
|
+
* Test standalone document output
|
|
1555
|
+
*/
|
|
1556
|
+
|
|
1557
|
+
void test_sup_sub(void) {
|
|
1558
|
+
int suite_failures = suite_start();
|
|
1559
|
+
print_suite_title("Superscript, Subscript, Underline, Delete, and Highlight Tests", false, true);
|
|
1560
|
+
|
|
1561
|
+
apex_options opts = apex_options_default();
|
|
1562
|
+
opts.enable_sup_sub = true;
|
|
1563
|
+
char *html;
|
|
1564
|
+
|
|
1565
|
+
/* ===== SUBSCRIPT TESTS ===== */
|
|
1566
|
+
|
|
1567
|
+
/* Test H~2~O for subscript 2 (paired tildes within word) */
|
|
1568
|
+
html = apex_markdown_to_html("H~2~O", 5, &opts);
|
|
1569
|
+
assert_contains(html, "<sub>2</sub>", "H~2~O creates subscript 2");
|
|
1570
|
+
assert_contains(html, "H<sub>2</sub>O", "Subscript within word");
|
|
1571
|
+
if (strstr(html, "<u>2</u>") == NULL) {
|
|
1572
|
+
test_result(true, "H~2~O is subscript, not underline");
|
|
1573
|
+
} else {
|
|
1574
|
+
test_result(false, "H~2~O incorrectly treated as underline");
|
|
1575
|
+
}
|
|
1576
|
+
apex_free_string(html);
|
|
1577
|
+
|
|
1578
|
+
/* Test H~2~SO~4~ for both 2 and 4 as subscripts */
|
|
1579
|
+
html = apex_markdown_to_html("H~2~SO~4~", 9, &opts);
|
|
1580
|
+
assert_contains(html, "<sub>2</sub>", "H~2~SO~4~ creates subscript 2");
|
|
1581
|
+
assert_contains(html, "<sub>4</sub>", "H~2~SO~4~ creates subscript 4");
|
|
1582
|
+
assert_contains(html, "H<sub>2</sub>SO<sub>4</sub>", "Multiple subscripts within word");
|
|
1583
|
+
apex_free_string(html);
|
|
1584
|
+
|
|
1585
|
+
/* Test subscript ends at sentence terminators */
|
|
1586
|
+
html = apex_markdown_to_html("H~2.O", 5, &opts);
|
|
1587
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at period");
|
|
1588
|
+
apex_free_string(html);
|
|
1589
|
+
|
|
1590
|
+
html = apex_markdown_to_html("H~2,O", 5, &opts);
|
|
1591
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at comma");
|
|
1592
|
+
apex_free_string(html);
|
|
1593
|
+
|
|
1594
|
+
html = apex_markdown_to_html("H~2;O", 5, &opts);
|
|
1595
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at semicolon");
|
|
1596
|
+
apex_free_string(html);
|
|
1597
|
+
|
|
1598
|
+
html = apex_markdown_to_html("H~2:O", 5, &opts);
|
|
1599
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at colon");
|
|
1600
|
+
apex_free_string(html);
|
|
1601
|
+
|
|
1602
|
+
html = apex_markdown_to_html("H~2!O", 5, &opts);
|
|
1603
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at exclamation");
|
|
1604
|
+
apex_free_string(html);
|
|
1605
|
+
|
|
1606
|
+
html = apex_markdown_to_html("H~2?O", 5, &opts);
|
|
1607
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at question mark");
|
|
1608
|
+
apex_free_string(html);
|
|
1609
|
+
|
|
1610
|
+
/* Test subscript ends at space */
|
|
1611
|
+
html = apex_markdown_to_html("H~2 O", 5, &opts);
|
|
1612
|
+
assert_contains(html, "<sub>2</sub>", "Subscript stops at space");
|
|
1613
|
+
assert_contains(html, "H<sub>2</sub> O", "Space after subscript");
|
|
1614
|
+
apex_free_string(html);
|
|
1615
|
+
|
|
1616
|
+
/* ===== SUPERSCRIPT TESTS ===== */
|
|
1617
|
+
|
|
1618
|
+
/* Test basic superscript */
|
|
1619
|
+
html = apex_markdown_to_html("m^2", 3, &opts);
|
|
1620
|
+
assert_contains(html, "<sup>2</sup>", "Basic superscript m^2");
|
|
1621
|
+
assert_contains(html, "m<sup>2</sup>", "Superscript in context");
|
|
1622
|
+
apex_free_string(html);
|
|
1623
|
+
|
|
1624
|
+
/* Test superscript ends at space */
|
|
1625
|
+
html = apex_markdown_to_html("x^2 + y^2", 9, &opts);
|
|
1626
|
+
assert_contains(html, "<sup>2</sup>", "Superscript stops at space");
|
|
1627
|
+
assert_contains(html, "x<sup>2</sup>", "First superscript");
|
|
1628
|
+
assert_contains(html, "y<sup>2</sup>", "Second superscript");
|
|
1629
|
+
apex_free_string(html);
|
|
1630
|
+
|
|
1631
|
+
/* Test superscript ends at sentence terminators */
|
|
1632
|
+
html = apex_markdown_to_html("x^2.", 4, &opts);
|
|
1633
|
+
assert_contains(html, "<sup>2</sup>", "Superscript stops at period");
|
|
1634
|
+
apex_free_string(html);
|
|
1635
|
+
|
|
1636
|
+
html = apex_markdown_to_html("x^2,", 4, &opts);
|
|
1637
|
+
assert_contains(html, "<sup>2</sup>", "Superscript stops at comma");
|
|
1638
|
+
apex_free_string(html);
|
|
1639
|
+
|
|
1640
|
+
html = apex_markdown_to_html("E = mc^2!", 9, &opts);
|
|
1641
|
+
assert_contains(html, "<sup>2</sup>", "Superscript stops at exclamation");
|
|
1642
|
+
apex_free_string(html);
|
|
1643
|
+
|
|
1644
|
+
/* Test multiple superscripts */
|
|
1645
|
+
html = apex_markdown_to_html("x^2 + y^2 = z^2", 15, &opts);
|
|
1646
|
+
assert_contains(html, "x<sup>2</sup>", "First superscript");
|
|
1647
|
+
assert_contains(html, "y<sup>2</sup>", "Second superscript");
|
|
1648
|
+
assert_contains(html, "z<sup>2</sup>", "Third superscript");
|
|
1649
|
+
apex_free_string(html);
|
|
1650
|
+
|
|
1651
|
+
/* ===== UNDERLINE TESTS ===== */
|
|
1652
|
+
|
|
1653
|
+
/* Test underline with tildes at word boundaries */
|
|
1654
|
+
html = apex_markdown_to_html("text ~underline~ text", 22, &opts);
|
|
1655
|
+
assert_contains(html, "<u>underline</u>", "Tildes at word boundaries create underline");
|
|
1656
|
+
assert_contains(html, "text <u>underline</u> text", "Underline in context");
|
|
1657
|
+
if (strstr(html, "<sub>underline</sub>") == NULL) {
|
|
1658
|
+
test_result(true, "~underline~ is underline, not subscript");
|
|
1659
|
+
} else {
|
|
1660
|
+
test_result(false, "~underline~ incorrectly treated as subscript");
|
|
1661
|
+
}
|
|
1662
|
+
apex_free_string(html);
|
|
1663
|
+
|
|
1664
|
+
/* Test underline with single word */
|
|
1665
|
+
html = apex_markdown_to_html("~h2o~", 6, &opts);
|
|
1666
|
+
assert_contains(html, "<u>h2o</u>", "~h2o~ creates underline");
|
|
1667
|
+
if (strstr(html, "<sub>") == NULL) {
|
|
1668
|
+
test_result(true, "~h2o~ is underline, not subscript");
|
|
1669
|
+
} else {
|
|
1670
|
+
test_result(false, "~h2o~ incorrectly treated as subscript");
|
|
1671
|
+
}
|
|
1672
|
+
apex_free_string(html);
|
|
1673
|
+
|
|
1674
|
+
/* ===== STRIKETHROUGH/DELETE TESTS ===== */
|
|
1675
|
+
|
|
1676
|
+
/* Test strikethrough with double tildes */
|
|
1677
|
+
html = apex_markdown_to_html("text ~~deleted text~~ text", 26, &opts);
|
|
1678
|
+
assert_contains(html, "<del>deleted text</del>", "Double tildes create strikethrough");
|
|
1679
|
+
assert_contains(html, "text <del>deleted text</del> text", "Strikethrough in context");
|
|
1680
|
+
apex_free_string(html);
|
|
1681
|
+
|
|
1682
|
+
/* Test strikethrough doesn't interfere with subscript */
|
|
1683
|
+
html = apex_markdown_to_html("H~2~O and ~~deleted~~", 21, &opts);
|
|
1684
|
+
assert_contains(html, "<sub>2</sub>", "Subscript still works with strikethrough");
|
|
1685
|
+
assert_contains(html, "<del>deleted</del>", "Strikethrough still works with subscript");
|
|
1686
|
+
apex_free_string(html);
|
|
1687
|
+
|
|
1688
|
+
/* Test strikethrough doesn't interfere with underline */
|
|
1689
|
+
html = apex_markdown_to_html("~underline~ and ~~deleted~~", 27, &opts);
|
|
1690
|
+
assert_contains(html, "<u>underline</u>", "Underline still works with strikethrough");
|
|
1691
|
+
assert_contains(html, "<del>deleted</del>", "Strikethrough still works with underline");
|
|
1692
|
+
apex_free_string(html);
|
|
1693
|
+
|
|
1694
|
+
/* ===== HIGHLIGHT TESTS ===== */
|
|
1695
|
+
|
|
1696
|
+
/* Test highlight with double equals */
|
|
1697
|
+
html = apex_markdown_to_html("text ==highlighted text== text", 30, &opts);
|
|
1698
|
+
assert_contains(html, "<mark>highlighted text</mark>", "Double equals create highlight");
|
|
1699
|
+
assert_contains(html, "text <mark>highlighted text</mark> text", "Highlight in context");
|
|
1700
|
+
apex_free_string(html);
|
|
1701
|
+
|
|
1702
|
+
/* Test highlight with single word */
|
|
1703
|
+
html = apex_markdown_to_html("==highlight==", 14, &opts);
|
|
1704
|
+
assert_contains(html, "<mark>highlight</mark>", "Single word highlight");
|
|
1705
|
+
apex_free_string(html);
|
|
1706
|
+
|
|
1707
|
+
/* Test highlight with multiple words */
|
|
1708
|
+
html = apex_markdown_to_html("==this is highlighted==", 24, &opts);
|
|
1709
|
+
assert_contains(html, "<mark>this is highlighted</mark>", "Multi-word highlight");
|
|
1710
|
+
apex_free_string(html);
|
|
1711
|
+
|
|
1712
|
+
/* Test highlight doesn't break Setext h1 */
|
|
1713
|
+
html = apex_markdown_to_html("Header\n==\n\n==highlight==", 25, &opts);
|
|
1714
|
+
assert_contains(html, "<h1", "Setext h1 still works");
|
|
1715
|
+
assert_contains(html, "Header</h1>", "Setext h1 content");
|
|
1716
|
+
assert_contains(html, "<mark>highlight</mark>", "Highlight after Setext h1");
|
|
1717
|
+
/* Verify the == after header is not treated as highlight */
|
|
1718
|
+
if (strstr(html, "<mark></mark>") == NULL || strstr(html, "<mark>\n</mark>") == NULL) {
|
|
1719
|
+
test_result(true, "== after Setext h1 doesn't break header");
|
|
1720
|
+
} else {
|
|
1721
|
+
test_result(false, "== after Setext h1 breaks header");
|
|
1722
|
+
}
|
|
1723
|
+
apex_free_string(html);
|
|
1724
|
+
|
|
1725
|
+
/* Test highlight with Setext h2 (===) */
|
|
1726
|
+
html = apex_markdown_to_html("Header\n---\n\n==highlight==", 25, &opts);
|
|
1727
|
+
assert_contains(html, "<h2", "Setext h2 still works");
|
|
1728
|
+
assert_contains(html, "Header</h2>", "Setext h2 content");
|
|
1729
|
+
assert_contains(html, "<mark>highlight</mark>", "Highlight after Setext h2");
|
|
1730
|
+
apex_free_string(html);
|
|
1731
|
+
|
|
1732
|
+
/* Test highlight in various contexts */
|
|
1733
|
+
html = apex_markdown_to_html("Before ==highlight== after", 26, &opts);
|
|
1734
|
+
assert_contains(html, "<mark>highlight</mark>", "Highlight in paragraph");
|
|
1735
|
+
apex_free_string(html);
|
|
1736
|
+
|
|
1737
|
+
html = apex_markdown_to_html("**bold ==highlight== bold**", 27, &opts);
|
|
1738
|
+
assert_contains(html, "<mark>highlight</mark>", "Highlight in bold");
|
|
1739
|
+
apex_free_string(html);
|
|
1740
|
+
|
|
1741
|
+
/* ===== INTERACTION TESTS ===== */
|
|
1742
|
+
|
|
1743
|
+
/* Test that sup/sub is disabled when option is off */
|
|
1744
|
+
apex_options no_sup_sub = apex_options_default();
|
|
1745
|
+
no_sup_sub.enable_sup_sub = false;
|
|
1746
|
+
html = apex_markdown_to_html("H^2 O", 5, &no_sup_sub);
|
|
1747
|
+
if (strstr(html, "<sup>") == NULL) {
|
|
1748
|
+
test_result(true, "Sup/sub disabled when option is off");
|
|
1749
|
+
} else {
|
|
1750
|
+
test_result(false, "Sup/sub not disabled when option is off");
|
|
1751
|
+
}
|
|
1752
|
+
apex_free_string(html);
|
|
1753
|
+
|
|
1754
|
+
/* Test that sup/sub is disabled in CommonMark mode */
|
|
1755
|
+
apex_options cm_opts = apex_options_for_mode(APEX_MODE_COMMONMARK);
|
|
1756
|
+
html = apex_markdown_to_html("H^2 O", 5, &cm_opts);
|
|
1757
|
+
if (strstr(html, "<sup>") == NULL) {
|
|
1758
|
+
test_result(true, "Sup/sub disabled in CommonMark mode");
|
|
1759
|
+
} else {
|
|
1760
|
+
test_result(false, "Sup/sub not disabled in CommonMark mode");
|
|
1761
|
+
}
|
|
1762
|
+
apex_free_string(html);
|
|
1763
|
+
|
|
1764
|
+
/* Test that sup/sub is enabled in Unified mode */
|
|
1765
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
1766
|
+
html = apex_markdown_to_html("H^2 O", 5, &unified_opts);
|
|
1767
|
+
assert_contains(html, "<sup>2</sup>", "Sup/sub enabled in Unified mode");
|
|
1768
|
+
apex_free_string(html);
|
|
1769
|
+
|
|
1770
|
+
/* Test that sup/sub is enabled in MultiMarkdown mode */
|
|
1771
|
+
apex_options mmd_opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
1772
|
+
html = apex_markdown_to_html("H^2 O", 5, &mmd_opts);
|
|
1773
|
+
assert_contains(html, "<sup>2</sup>", "Sup/sub enabled in MultiMarkdown mode");
|
|
1774
|
+
apex_free_string(html);
|
|
1775
|
+
|
|
1776
|
+
/* Test that ^ and ~ are preserved in math spans */
|
|
1777
|
+
opts.enable_math = true;
|
|
1778
|
+
html = apex_markdown_to_html("Equation: $E=mc^2$", 18, &opts);
|
|
1779
|
+
assert_contains(html, "E=mc^2", "Superscript preserved in math span");
|
|
1780
|
+
if (strstr(html, "<sup>2</sup>") == NULL) {
|
|
1781
|
+
test_result(true, "Superscript not processed inside math span");
|
|
1782
|
+
} else {
|
|
1783
|
+
test_result(false, "Superscript incorrectly processed inside math span");
|
|
1784
|
+
}
|
|
1785
|
+
apex_free_string(html);
|
|
1786
|
+
|
|
1787
|
+
/* Test that ^ is preserved in footnote references */
|
|
1788
|
+
html = apex_markdown_to_html("Text[^ref]", 10, &opts);
|
|
1789
|
+
if (strstr(html, "<sup>ref</sup>") == NULL) {
|
|
1790
|
+
test_result(true, "Superscript not processed in footnote reference");
|
|
1791
|
+
} else {
|
|
1792
|
+
test_result(false, "Superscript incorrectly processed in footnote reference");
|
|
1793
|
+
}
|
|
1794
|
+
apex_free_string(html);
|
|
1795
|
+
|
|
1796
|
+
/* Test that ~ is preserved in critic markup */
|
|
1797
|
+
opts.enable_critic_markup = true;
|
|
1798
|
+
html = apex_markdown_to_html("{~~old~>new~~}", 13, &opts);
|
|
1799
|
+
if (strstr(html, "<sub>old</sub>") == NULL) {
|
|
1800
|
+
test_result(true, "Subscript not processed in critic markup");
|
|
1801
|
+
} else {
|
|
1802
|
+
test_result(false, "Subscript incorrectly processed in critic markup");
|
|
1803
|
+
}
|
|
1804
|
+
apex_free_string(html);
|
|
1805
|
+
|
|
1806
|
+
bool had_failures = suite_end(suite_failures);
|
|
1807
|
+
print_suite_title("Superscript, Subscript, Underline, Delete, and Highlight Tests", had_failures, false);
|
|
1808
|
+
}
|
|
1809
|
+
|
|
1810
|
+
/**
|
|
1811
|
+
* Test mixed list markers
|
|
1812
|
+
*/
|
|
1813
|
+
|
|
1814
|
+
void test_mixed_lists(void) {
|
|
1815
|
+
int suite_failures = suite_start();
|
|
1816
|
+
print_suite_title("Mixed List Markers Tests", false, true);
|
|
1817
|
+
|
|
1818
|
+
char *html;
|
|
1819
|
+
|
|
1820
|
+
/* Test mixed markers in unified mode (should merge) */
|
|
1821
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
1822
|
+
const char *mixed_list = "1. First item\n* Second item\n* Third item";
|
|
1823
|
+
html = apex_markdown_to_html(mixed_list, strlen(mixed_list), &unified_opts);
|
|
1824
|
+
assert_contains(html, "<ol>", "Mixed list creates ordered list");
|
|
1825
|
+
assert_contains(html, "<li>First item</li>", "First item in list");
|
|
1826
|
+
assert_contains(html, "<li>Second item</li>", "Second item in list");
|
|
1827
|
+
assert_contains(html, "<li>Third item</li>", "Third item in list");
|
|
1828
|
+
/* Should have only one list, not two */
|
|
1829
|
+
const char *first_ol = strstr(html, "<ol>");
|
|
1830
|
+
const char *second_ol = first_ol ? strstr(first_ol + 1, "<ol>") : NULL;
|
|
1831
|
+
if (second_ol == NULL) {
|
|
1832
|
+
test_result(true, "Mixed markers create single list in unified mode");
|
|
1833
|
+
} else {
|
|
1834
|
+
test_result(false, "Mixed markers create multiple lists in unified mode");
|
|
1835
|
+
}
|
|
1836
|
+
apex_free_string(html);
|
|
1837
|
+
|
|
1838
|
+
/* Test mixed markers in CommonMark mode (should be separate lists) */
|
|
1839
|
+
apex_options cm_opts = apex_options_for_mode(APEX_MODE_COMMONMARK);
|
|
1840
|
+
html = apex_markdown_to_html(mixed_list, strlen(mixed_list), &cm_opts);
|
|
1841
|
+
assert_contains(html, "<ol>", "First list exists");
|
|
1842
|
+
assert_contains(html, "<ul>", "Second list exists");
|
|
1843
|
+
/* Should have two separate lists */
|
|
1844
|
+
first_ol = strstr(html, "<ol>");
|
|
1845
|
+
second_ol = first_ol ? strstr(first_ol + 1, "<ol>") : NULL;
|
|
1846
|
+
const char *first_ul = strstr(html, "<ul>");
|
|
1847
|
+
if (second_ol == NULL && first_ul != NULL) {
|
|
1848
|
+
test_result(true, "Mixed markers create separate lists in CommonMark mode");
|
|
1849
|
+
} else {
|
|
1850
|
+
test_result(false, "Mixed markers not handled correctly in CommonMark mode");
|
|
1851
|
+
}
|
|
1852
|
+
apex_free_string(html);
|
|
1853
|
+
|
|
1854
|
+
/* Test mixed markers with unordered first */
|
|
1855
|
+
const char *mixed_unordered = "* First item\n1. Second item\n2. Third item";
|
|
1856
|
+
html = apex_markdown_to_html(mixed_unordered, strlen(mixed_unordered), &unified_opts);
|
|
1857
|
+
assert_contains(html, "<ul>", "Unordered-first mixed list creates unordered list");
|
|
1858
|
+
assert_contains(html, "<li>First item</li>", "First unordered item");
|
|
1859
|
+
assert_contains(html, "<li>Second item</li>", "Second item inherits unordered");
|
|
1860
|
+
apex_free_string(html);
|
|
1861
|
+
|
|
1862
|
+
/* Test that allow_mixed_list_markers=false creates separate lists even in unified mode */
|
|
1863
|
+
unified_opts.allow_mixed_list_markers = false;
|
|
1864
|
+
html = apex_markdown_to_html(mixed_list, strlen(mixed_list), &unified_opts);
|
|
1865
|
+
first_ol = strstr(html, "<ol>");
|
|
1866
|
+
second_ol = first_ol ? strstr(first_ol + 1, "<ol>") : NULL;
|
|
1867
|
+
first_ul = strstr(html, "<ul>");
|
|
1868
|
+
if (second_ol == NULL && first_ul != NULL) {
|
|
1869
|
+
test_result(true, "--no-mixed-lists disables mixed list merging");
|
|
1870
|
+
} else {
|
|
1871
|
+
test_result(false, "--no-mixed-lists does not disable mixed list merging");
|
|
1872
|
+
}
|
|
1873
|
+
apex_free_string(html);
|
|
1874
|
+
|
|
1875
|
+
bool had_failures = suite_end(suite_failures);
|
|
1876
|
+
print_suite_title("Mixed List Markers Tests", had_failures, false);
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
/**
|
|
1880
|
+
* Test unsafe mode (raw HTML handling)
|
|
1881
|
+
*/
|
|
1882
|
+
|
|
1883
|
+
void test_unsafe_mode(void) {
|
|
1884
|
+
int suite_failures = suite_start();
|
|
1885
|
+
print_suite_title("Unsafe Mode Tests", false, true);
|
|
1886
|
+
|
|
1887
|
+
char *html;
|
|
1888
|
+
|
|
1889
|
+
/* Test that unsafe mode allows raw HTML by default in unified mode */
|
|
1890
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
1891
|
+
const char *raw_html = "<div>Raw HTML content</div>";
|
|
1892
|
+
html = apex_markdown_to_html(raw_html, strlen(raw_html), &unified_opts);
|
|
1893
|
+
assert_contains(html, "<div>Raw HTML content</div>", "Raw HTML allowed in unified mode");
|
|
1894
|
+
if (strstr(html, "raw HTML omitted") == NULL && strstr(html, "omitted") == NULL) {
|
|
1895
|
+
test_result(true, "Raw HTML preserved in unified mode (unsafe default)");
|
|
1896
|
+
} else {
|
|
1897
|
+
test_result(false, "Raw HTML not preserved in unified mode");
|
|
1898
|
+
}
|
|
1899
|
+
apex_free_string(html);
|
|
1900
|
+
|
|
1901
|
+
/* Test that unsafe mode blocks raw HTML in CommonMark mode */
|
|
1902
|
+
apex_options cm_opts = apex_options_for_mode(APEX_MODE_COMMONMARK);
|
|
1903
|
+
html = apex_markdown_to_html(raw_html, strlen(raw_html), &cm_opts);
|
|
1904
|
+
if (strstr(html, "raw HTML omitted") != NULL || strstr(html, "omitted") != NULL) {
|
|
1905
|
+
tests_passed++;
|
|
1906
|
+
tests_run++;
|
|
1907
|
+
if (!errors_only_output) {
|
|
1908
|
+
printf(COLOR_GREEN "✓" COLOR_RESET " Raw HTML blocked in CommonMark mode (safe default)\n");
|
|
1909
|
+
}
|
|
1910
|
+
} else if (strstr(html, "<div>Raw HTML content</div>") == NULL) {
|
|
1911
|
+
tests_passed++;
|
|
1912
|
+
tests_run++;
|
|
1913
|
+
if (!errors_only_output) {
|
|
1914
|
+
printf(COLOR_GREEN "✓" COLOR_RESET " Raw HTML blocked in CommonMark mode (safe default)\n");
|
|
1915
|
+
}
|
|
1916
|
+
} else {
|
|
1917
|
+
tests_failed++;
|
|
1918
|
+
tests_run++;
|
|
1919
|
+
printf(COLOR_RED "✗" COLOR_RESET " Raw HTML not blocked in CommonMark mode\n");
|
|
1920
|
+
}
|
|
1921
|
+
apex_free_string(html);
|
|
1922
|
+
|
|
1923
|
+
/* Test that unsafe=false blocks raw HTML even in unified mode */
|
|
1924
|
+
unified_opts.unsafe = false;
|
|
1925
|
+
html = apex_markdown_to_html(raw_html, strlen(raw_html), &unified_opts);
|
|
1926
|
+
if (strstr(html, "raw HTML omitted") != NULL || strstr(html, "omitted") != NULL) {
|
|
1927
|
+
test_result(true, "--no-unsafe blocks raw HTML");
|
|
1928
|
+
} else if (strstr(html, "<div>Raw HTML content</div>") == NULL) {
|
|
1929
|
+
test_result(true, "--no-unsafe blocks raw HTML");
|
|
1930
|
+
} else {
|
|
1931
|
+
test_result(false, "--no-unsafe does not block raw HTML");
|
|
1932
|
+
}
|
|
1933
|
+
apex_free_string(html);
|
|
1934
|
+
|
|
1935
|
+
/* Test that unsafe=true allows raw HTML even in CommonMark mode */
|
|
1936
|
+
cm_opts.unsafe = true;
|
|
1937
|
+
html = apex_markdown_to_html(raw_html, strlen(raw_html), &cm_opts);
|
|
1938
|
+
assert_contains(html, "<div>Raw HTML content</div>", "Raw HTML allowed with unsafe=true");
|
|
1939
|
+
apex_free_string(html);
|
|
1940
|
+
|
|
1941
|
+
/* Test HTML comments in unsafe mode */
|
|
1942
|
+
const char *html_comment = "<!-- This is a comment -->";
|
|
1943
|
+
unified_opts.unsafe = true;
|
|
1944
|
+
html = apex_markdown_to_html(html_comment, strlen(html_comment), &unified_opts);
|
|
1945
|
+
assert_contains(html, "<!-- This is a comment -->", "HTML comments preserved in unsafe mode");
|
|
1946
|
+
apex_free_string(html);
|
|
1947
|
+
|
|
1948
|
+
/* Test HTML comments in safe mode */
|
|
1949
|
+
unified_opts.unsafe = false;
|
|
1950
|
+
html = apex_markdown_to_html(html_comment, strlen(html_comment), &unified_opts);
|
|
1951
|
+
if (strstr(html, "raw HTML omitted") != NULL || strstr(html, "omitted") != NULL) {
|
|
1952
|
+
test_result(true, "HTML comments blocked in safe mode");
|
|
1953
|
+
} else {
|
|
1954
|
+
test_result(false, "HTML comments not blocked in safe mode");
|
|
1955
|
+
}
|
|
1956
|
+
apex_free_string(html);
|
|
1957
|
+
|
|
1958
|
+
/* Test script tags are handled according to unsafe setting */
|
|
1959
|
+
const char *script_tag = "<script>alert('xss')</script>";
|
|
1960
|
+
unified_opts.unsafe = true;
|
|
1961
|
+
html = apex_markdown_to_html(script_tag, strlen(script_tag), &unified_opts);
|
|
1962
|
+
/* In unsafe mode, script tags might be preserved or escaped depending on cmark-gfm */
|
|
1963
|
+
/* Just verify it's handled somehow */
|
|
1964
|
+
if (strstr(html, "script") != NULL || strstr(html, "omitted") != NULL) {
|
|
1965
|
+
test_result(true, "Script tags handled in unsafe mode");
|
|
1966
|
+
} else {
|
|
1967
|
+
test_result(false, "Script tags not handled in unsafe mode");
|
|
1968
|
+
}
|
|
1969
|
+
apex_free_string(html);
|
|
1970
|
+
|
|
1971
|
+
bool had_failures = suite_end(suite_failures);
|
|
1972
|
+
print_suite_title("Unsafe Mode Tests", had_failures, false);
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
/**
|
|
1976
|
+
* Test Insert Syntax (++text++)
|
|
1977
|
+
*/
|
|
1978
|
+
void test_insert_syntax(void) {
|
|
1979
|
+
int suite_failures = suite_start();
|
|
1980
|
+
print_suite_title("Insert Syntax Tests", false, true);
|
|
1981
|
+
|
|
1982
|
+
apex_options opts = apex_options_default();
|
|
1983
|
+
char *html;
|
|
1984
|
+
|
|
1985
|
+
/* Test basic insert without IAL */
|
|
1986
|
+
html = apex_markdown_to_html("Text ++inserted++ here", 23, &opts);
|
|
1987
|
+
assert_contains(html, "<ins>inserted</ins>", "Basic insert syntax");
|
|
1988
|
+
apex_free_string(html);
|
|
1989
|
+
|
|
1990
|
+
/* Test insert with Kramdown-style IAL */
|
|
1991
|
+
html = apex_markdown_to_html("Text ++inserted++{: .class} here", 33, &opts);
|
|
1992
|
+
assert_contains(html, "<ins", "Insert with IAL creates ins tag");
|
|
1993
|
+
assert_contains(html, "class=\"class\"", "Insert with IAL has class");
|
|
1994
|
+
assert_contains(html, "inserted", "Insert with IAL contains text");
|
|
1995
|
+
apex_free_string(html);
|
|
1996
|
+
|
|
1997
|
+
/* Test insert with Pandoc-style IAL */
|
|
1998
|
+
html = apex_markdown_to_html("Text ++inserted++{#id .class} here", 35, &opts);
|
|
1999
|
+
assert_contains(html, "<ins", "Insert with Pandoc IAL creates ins tag");
|
|
2000
|
+
assert_contains(html, "id=\"id\"", "Insert with Pandoc IAL has ID");
|
|
2001
|
+
assert_contains(html, "class=\"class\"", "Insert with Pandoc IAL has class");
|
|
2002
|
+
apex_free_string(html);
|
|
2003
|
+
|
|
2004
|
+
/* Test insert with multiple classes */
|
|
2005
|
+
html = apex_markdown_to_html("Text ++inserted++{: .class1 .class2} here", 39, &opts);
|
|
2006
|
+
assert_contains(html, "class=\"class1 class2\"", "Insert with multiple classes");
|
|
2007
|
+
apex_free_string(html);
|
|
2008
|
+
|
|
2009
|
+
/* Test insert does not interfere with CriticMarkup */
|
|
2010
|
+
opts.enable_critic_markup = true;
|
|
2011
|
+
opts.critic_mode = 2; /* CRITIC_MARKUP */
|
|
2012
|
+
html = apex_markdown_to_html("Text {++critic++} and ++plain++ here", 38, &opts);
|
|
2013
|
+
assert_contains(html, "<ins class=\"critic\">critic</ins>", "CriticMarkup insert still works");
|
|
2014
|
+
assert_contains(html, "<ins>plain</ins>", "Plain insert still works");
|
|
2015
|
+
apex_free_string(html);
|
|
2016
|
+
|
|
2017
|
+
/* Test insert in code blocks is not processed */
|
|
2018
|
+
html = apex_markdown_to_html("```\n++code++\n```", 18, &opts);
|
|
2019
|
+
assert_contains(html, "++code++", "Insert in code block not processed");
|
|
2020
|
+
assert_not_contains(html, "<ins>code</ins>", "Insert in code block not converted");
|
|
2021
|
+
apex_free_string(html);
|
|
2022
|
+
|
|
2023
|
+
/* Test insert in inline code is not processed */
|
|
2024
|
+
html = apex_markdown_to_html("Text `++code++` here", 20, &opts);
|
|
2025
|
+
assert_contains(html, "++code++", "Insert in inline code not processed");
|
|
2026
|
+
assert_not_contains(html, "<ins>code</ins>", "Insert in inline code not converted");
|
|
2027
|
+
apex_free_string(html);
|
|
2028
|
+
|
|
2029
|
+
/* Test insert with markdown inside */
|
|
2030
|
+
html = apex_markdown_to_html("Text ++*italic*++ here", 23, &opts);
|
|
2031
|
+
assert_contains(html, "<ins>", "Insert tag present");
|
|
2032
|
+
assert_contains(html, "<em>italic</em>", "Markdown inside insert processed");
|
|
2033
|
+
apex_free_string(html);
|
|
2034
|
+
|
|
2035
|
+
/* Test insert with IAL and markdown inside */
|
|
2036
|
+
html = apex_markdown_to_html("Text ++*italic*++{: .highlight} here", 35, &opts);
|
|
2037
|
+
assert_contains(html, "<ins", "Insert with IAL and markdown creates ins tag");
|
|
2038
|
+
assert_contains(html, "class=\"highlight\"", "Insert with IAL has class");
|
|
2039
|
+
assert_contains(html, "<em>italic</em>", "Markdown inside insert with IAL processed");
|
|
2040
|
+
apex_free_string(html);
|
|
2041
|
+
|
|
2042
|
+
bool had_failures = suite_end(suite_failures);
|
|
2043
|
+
print_suite_title("Insert Syntax Tests", had_failures, false);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
/**
|
|
2047
|
+
* Test image captions -> figure/figcaption wrapping
|
|
2048
|
+
* Enabled by default in MultiMarkdown and Unified modes, configurable via options.
|
|
2049
|
+
*/
|
|
2050
|
+
void test_image_captions(void) {
|
|
2051
|
+
int suite_failures = suite_start();
|
|
2052
|
+
print_suite_title("Image Captions Tests", false, true);
|
|
2053
|
+
|
|
2054
|
+
const char *md_basic =
|
|
2055
|
+
"\n\n"
|
|
2056
|
+
"\n\n"
|
|
2057
|
+
"\n";
|
|
2058
|
+
|
|
2059
|
+
/* MultiMarkdown mode: captions enabled by default */
|
|
2060
|
+
apex_options mmd_opts = apex_options_for_mode(APEX_MODE_MULTIMARKDOWN);
|
|
2061
|
+
char *html = apex_markdown_to_html(md_basic, strlen(md_basic), &mmd_opts);
|
|
2062
|
+
assert_contains(html, "<figure>", "MMD: figures generated");
|
|
2063
|
+
assert_contains(html, "<img src=\"/img/basic.png\"", "MMD: basic image present");
|
|
2064
|
+
assert_contains(html, "<figcaption>Alt only</figcaption>", "MMD: caption from alt text");
|
|
2065
|
+
assert_contains(html, "<img src=\"/img/title.png\"", "MMD: titled image present");
|
|
2066
|
+
assert_contains(html, "<figcaption>Title caption</figcaption>", "MMD: caption from title text");
|
|
2067
|
+
assert_not_contains(html, "<figure><img src=\"/img/empty.png\"", "MMD: no figure for empty alt/title image");
|
|
2068
|
+
apex_free_string(html);
|
|
2069
|
+
|
|
2070
|
+
/* Unified mode: captions enabled by default */
|
|
2071
|
+
apex_options unified_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
2072
|
+
html = apex_markdown_to_html(md_basic, strlen(md_basic), &unified_opts);
|
|
2073
|
+
assert_contains(html, "<figure>", "Unified: figures generated");
|
|
2074
|
+
assert_contains(html, "<figcaption>Alt only</figcaption>", "Unified: caption from alt text");
|
|
2075
|
+
assert_contains(html, "<figcaption>Title caption</figcaption>", "Unified: caption from title text");
|
|
2076
|
+
assert_not_contains(html, "<figure><img src=\"/img/empty.png\"", "Unified: no figure for empty alt/title image");
|
|
2077
|
+
apex_free_string(html);
|
|
2078
|
+
|
|
2079
|
+
/* Explicitly disabling captions should produce plain <img> tags */
|
|
2080
|
+
apex_options disabled_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
2081
|
+
disabled_opts.enable_image_captions = false;
|
|
2082
|
+
html = apex_markdown_to_html(md_basic, strlen(md_basic), &disabled_opts);
|
|
2083
|
+
assert_not_contains(html, "<figure>", "Disabled: no figures generated");
|
|
2084
|
+
assert_not_contains(html, "<figcaption>", "Disabled: no figcaptions generated");
|
|
2085
|
+
assert_contains(html, "<img src=\"/img/basic.png\"", "Disabled: basic image present");
|
|
2086
|
+
apex_free_string(html);
|
|
2087
|
+
|
|
2088
|
+
/* caption="TEXT" on image adds figure/figcaption even when --image-captions is off */
|
|
2089
|
+
const char *md_caption_attr = "{caption=\"Explicit caption\"}\n";
|
|
2090
|
+
apex_options no_captions_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
2091
|
+
no_captions_opts.enable_image_captions = false;
|
|
2092
|
+
html = apex_markdown_to_html(md_caption_attr, strlen(md_caption_attr), &no_captions_opts);
|
|
2093
|
+
assert_contains(html, "<figure>", "caption=: figure present");
|
|
2094
|
+
assert_contains(html, "<figcaption>Explicit caption</figcaption>", "caption=: figcaption text");
|
|
2095
|
+
assert_not_contains(html, "caption=\"", "caption=: caption attr stripped from img");
|
|
2096
|
+
apex_free_string(html);
|
|
2097
|
+
|
|
2098
|
+
/* --title-captions-only: only images with title get captions; alt-only images do not */
|
|
2099
|
+
const char *md_alt_and_title =
|
|
2100
|
+
"\n\n"
|
|
2101
|
+
"\n";
|
|
2102
|
+
apex_options title_only_opts = apex_options_for_mode(APEX_MODE_UNIFIED);
|
|
2103
|
+
title_only_opts.enable_image_captions = true;
|
|
2104
|
+
title_only_opts.title_captions_only = true;
|
|
2105
|
+
html = apex_markdown_to_html(md_alt_and_title, strlen(md_alt_and_title), &title_only_opts);
|
|
2106
|
+
assert_contains(html, "<figcaption>Title caption</figcaption>", "title_captions_only: caption from title");
|
|
2107
|
+
assert_not_contains(html, "<figcaption>Alt only</figcaption>", "title_captions_only: no caption from alt");
|
|
2108
|
+
apex_free_string(html);
|
|
2109
|
+
|
|
2110
|
+
bool had_failures = suite_end(suite_failures);
|
|
2111
|
+
print_suite_title("Image Captions Tests", had_failures, false);
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
/**
|
|
2115
|
+
* Test image embedding
|
|
2116
|
+
*/
|