. "$BST_LIB" # cmark 0.31.0 is the reference CommonMark implementation -- the parser the spec # is validated against -- shipped here as a static archive plus the cmark(1) CLI. # # This suite is unlike its 76-* neighbours in one way that shapes everything # below. libmxml, libdaemon, libatomic-ops and gmp ship a library and nothing that # runs, so their suites can only assert that the payload is real and complete, and # the runtime evidence has to live in the ticket's design doc. cmark ships its own # consumer: /usr/bin/cmark links the archive statically and is installed beside # it. So the second half of this file asserts what no header-and-symbols check # can -- that the parser actually PARSES, on this arm, and renders the bytes # CommonMark says it should. Those expectations were taken from a native build of # this same source at this same SRCREV, not written from memory of the spec. # # Four things pinned here were measured rather than assumed, and each would be # wrong if copied from a neighbour: # # 1. RAW HTML IS FILTERED BY DEFAULT. `
x
` renders as # ``, not as itself. cmark reversed this default: # CMARK_OPT_SAFE is now a no-op kept only for API compatibility (the header # says so in as many words) and CMARK_OPT_UNSAFE (1 << 17) is what turns # filtering off. A suite that asserted raw HTML passes through would fail # against a correct port, so both directions are asserted. # 2. Cflags AND Libs ARE NON-EMPTY AT THE SOURCE and pkgconf filters them. # libcmark.pc carries `-I${includedir}` and `-L${libdir}`, so --cflags prints # nothing and --libs prints only -lcmark -- while --keep-system-cflags and # --keep-system-libs RESTORE both. That is the exact opposite of # 76-libmxml.test, where the same empty output proves the fields were never # there; the restoring pair is what distinguishes the two cases. # 3. THE INSTALLED CMAKE PACKAGE NAMES THE LIBRARY TYPE. cmark-targets.cmake # says `add_library(cmark::cmark STATIC IMPORTED)`. That single line is the # on-target proof that BUILD_SHARED_LIBS=OFF reached the build and survived # into what consumers see -- stronger than "no .so is installed", which is # also true of a build that simply failed to produce one. # 4. NO TABLES. Pipe tables are a GFM extension, not CommonMark, and this is # cmark rather than cmark-gfm: a table renders as a literal paragraph. It is # asserted so that swapping in cmark-gfm later is a visible test change # rather than a silent behavioural one. root=${BST_ROOT:-} bin=$root/usr/bin/cmark inc=$root/usr/include/cmark.h incv=$root/usr/include/cmark_version.h ince=$root/usr/include/cmark_export.h pc=$root/usr/lib/pkgconfig/libcmark.pc cm=$root/usr/lib/cmake/cmark # The library this package ships, on whichever arm it was built. cmake's # BUILD_SHARED_LIBS is one toggle, so a converted cmark ships libcmark.so and NO # archive -- while every case below that reads the library's BYTES named the # archive by path and would go red on a conversion that worked (BRINTOS-1930). # Resolved once, here. The archive is preferred where both exist, so the static # arm reads exactly the bytes it always read; the fallback keeps the two presence # cases below reporting a path rather than an empty string when nothing shipped. lib=$(bst_ps_lib "$root/usr/lib/libcmark.a" "$root/usr/lib/libcmark.so" "$root/usr/lib/libcmark.so.*") : "${lib:=$root/usr/lib/libcmark.a}" # ---------------------------------------------------------------- payload ----- check cmark/bin-present test -f "$bin" check cmark/bin-executable test -x "$bin" check cmark/header-present test -f "$inc" check cmark/header-nonempty test -s "$inc" check cmark/verhdr-present test -f "$incv" check cmark/exphdr-present test -f "$ince" check cmark/pc-present test -f "$pc" check cmark/lib-present test -f "$lib" check cmark/lib-nonempty test -s "$lib" # --------------------------------------------------------------- cmark.h ------ check_out cmark/hdr-guard "#ifndef CMARK_H" cat "$inc" check_out cmark/hdr-extern-c 'extern "C" {' cat "$inc" # cmark.h is self-sufficient: it pulls stdio.h for the FILE* entry points and its # own two generated headers, so a consumer includes exactly one file. check_out cmark/hdr-inc-stdio "#include " cat "$inc" check_out cmark/hdr-inc-export "#include " cat "$inc" check_out cmark/hdr-inc-version "#include " cat "$inc" # The four opaque types a caller holds, and the memory-allocator struct that makes # cmark_node_new_with_mem / cmark_parser_new_with_mem usable. for t in "typedef struct cmark_node cmark_node;" \ "typedef struct cmark_parser cmark_parser;" \ "typedef struct cmark_iter cmark_iter;" \ "} cmark_mem;"; do check_out "cmark/type-$(printf '%s' "$t" | tr -cd 'a-z_' | cut -c1-24)" "$t" cat "$inc" done # The four enums a caller switches on. check_out cmark/enum-node-type "} cmark_node_type;" cat "$inc" check_out cmark/enum-list-type "} cmark_list_type;" cat "$inc" check_out cmark/enum-delim-type "} cmark_delim_type;" cat "$inc" check_out cmark/enum-event-type "} cmark_event_type;" cat "$inc" # The option bits. SAFE and UNSAFE are asserted by VALUE because their relationship # is the surprise (note 1): SAFE is (1 << 3) and inert, UNSAFE is (1 << 17) and is # the one that does anything. check_out cmark/opt-default "#define CMARK_OPT_DEFAULT 0" cat "$inc" check_out cmark/opt-sourcepos "#define CMARK_OPT_SOURCEPOS (1 << 1)" cat "$inc" check_out cmark/opt-hardbreaks "#define CMARK_OPT_HARDBREAKS (1 << 2)" cat "$inc" check_out cmark/opt-safe "#define CMARK_OPT_SAFE (1 << 3)" cat "$inc" check_out cmark/opt-unsafe "#define CMARK_OPT_UNSAFE (1 << 17)" cat "$inc" check_out cmark/opt-nobreaks "#define CMARK_OPT_NOBREAKS (1 << 4)" cat "$inc" check_out cmark/opt-normalize "#define CMARK_OPT_NORMALIZE (1 << 8)" cat "$inc" check_out cmark/opt-validate "#define CMARK_OPT_VALIDATE_UTF8 (1 << 9)" cat "$inc" check_out cmark/opt-smart "#define CMARK_OPT_SMART (1 << 10)" cat "$inc" # SAFE is documented as retained-but-inert; the comment is the API contract that # explains why asserting it as a no-op above is correct rather than a stale value. check_out cmark/opt-safe-noop "defined here for API compatibility" cat "$inc" # The four pre-rename node aliases upstream keeps for source compatibility. for a in "CMARK_NODE_HEADER CMARK_NODE_HEADING" \ "CMARK_NODE_HRULE CMARK_NODE_THEMATIC_BREAK" \ "CMARK_NODE_HTML CMARK_NODE_HTML_BLOCK" \ "CMARK_NODE_INLINE_HTML CMARK_NODE_HTML_INLINE"; do check_out "cmark/alias-$(printf '%s' "$a" | cut -d' ' -f1)" "#define $a" cat "$inc" done # ------------------------------------------------------- generated headers ---- check_out cmark/ver-string "#define CMARK_VERSION_STRING \"0.31.0\"" cat "$incv" check_out cmark/ver-macro "#define CMARK_VERSION ((0 << 16) | (31 << 8) | 0)" cat "$incv" check_eq cmark/ver-string-is-0310 "0.31.0" \ "$(awk -F'"' '/CMARK_VERSION_STRING/{print $2}' "$incv")" # cmark_export.h resolves CMARK_EXPORT to NOTHING down every branch here -- the # static-define branch by definition, and the shared branch because # generate_export_header emitted empty visibility macros for this compiler. That # is why a pkg-config consumer, which never sees -DCMARK_STATIC_DEFINE (note 2), # still compiles: there is no branch in which the macro expands to an attribute. check_out cmark/exp-guard "#ifndef CMARK_EXPORT_H" cat "$ince" check_out cmark/exp-static-brace "#ifdef CMARK_STATIC_DEFINE" cat "$ince" check_out cmark/exp-deprecated "__attribute__ ((__deprecated__))" cat "$ince" check cmark/exp-no-visibility sh -c '! grep -q "visibility" "$1"' _ "$ince" # ------------------------------------------------------------ libcmark.pc ----- check_out cmark/pc-name "Name: libcmark" cat "$pc" check_out cmark/pc-version "Version: 0.31.0" cat "$pc" check_out cmark/pc-desc "CommonMark parsing, rendering, and manipulation" cat "$pc" check_out cmark/pc-prefix "prefix=/usr" cat "$pc" check_out cmark/pc-libdir "libdir=/usr/lib" cat "$pc" check_out cmark/pc-includedir "includedir=/usr/include" cat "$pc" # Both fields are non-empty in the file. See note 2 -- this is what the pkgconf # --keep-system-* pair below is measured against. check_out cmark/pc-libs-field 'Libs: -L${libdir} -lcmark' cat "$pc" check_out cmark/pc-cflags-field 'Cflags: -I${includedir}' cat "$pc" # No Requires: cmark depends on nothing but libc, which is why it was a one-line # image addition rather than a dependency chain. check cmark/pc-no-requires sh -c '! grep -q "^Requires" "$1"' _ "$pc" # ------------------------------------------------------- cmake package -------- check cmark/cmake-config test -f "$cm/cmark-config.cmake" check cmark/cmake-version test -f "$cm/cmark-config-version.cmake" check cmark/cmake-targets test -f "$cm/cmark-targets.cmake" check cmark/cmake-targets-rel test -f "$cm/cmark-targets-release.cmake" # Note 3: the library type, stated by the build itself -- and therefore a # statement about the ARM, which is why it is read per arm. All three lines are # derived from BUILD_SHARED_LIBS: the imported type, the STATIC_DEFINE usage # requirement and the IMPORTED_LOCATION all follow it, so once the package flip # allow-lists cmark they say SHARED, drop the define and point at the .so. # Asserting the static spellings outright would fail cmark for a conversion that # worked, which is the class BRINTOS-1930 measured on libpcre2; asserting the # pair keeps what these are for, since an export set disagreeing with the library # beside it misbuilds a cmake consumer in either direction. if bst_ps_converted "$root/usr/lib/libcmark.so" "$root/usr/lib/libcmark.so.*"; then check_out cmark/cmake-shared-imported "add_library(cmark::cmark SHARED IMPORTED)" \ cat "$cm/cmark-targets.cmake" check cmark/cmake-no-static-define \ sh -c '! grep -q CMARK_STATIC_DEFINE "$1"' _ "$cm/cmark-targets.cmake" check_out cmark/cmake-loc-shared "libcmark.so" cat "$cm/cmark-targets-release.cmake" else check_out cmark/cmake-static-imported "add_library(cmark::cmark STATIC IMPORTED)" \ cat "$cm/cmark-targets.cmake" check_out cmark/cmake-static-define "INTERFACE_COMPILE_DEFINITIONS \"CMARK_STATIC_DEFINE\"" \ cat "$cm/cmark-targets.cmake" check_out cmark/cmake-loc-archive "libcmark.a" cat "$cm/cmark-targets-release.cmake" fi check_out cmark/cmake-loc-binary "bin/cmark" cat "$cm/cmark-targets-release.cmake" check_out cmark/cmake-pkgversion "0.31.0" cat "$cm/cmark-config-version.cmake" # ---------------------------------------------------------------- archive ----- # The ar magic is the static arm's, and only its. A converted cmark ships a wasm # shared object here instead; that it is a usable one is asserted by the # bst_lib_shape case under "packaging policy" below, so this one skips rather than # inventing a second magic number to match. if bst_ps_converted "$root/usr/lib/libcmark.so" "$root/usr/lib/libcmark.so.*"; then bst_skip cmark/lib-archive "libcmark.so shipped; the ar magic is the static arm's" else check_out cmark/lib-archive "!" head -c 8 "$lib" fi # Flatten the archive to printable text once, the formulation 74-libtinyxml2 and # 76-libmxml use: GNU grep suppresses matches inside binary data, and busybox tr # does not handle [:print:] under -c, so the octal range is what both agree on. flat=${TMPDIR:-/tmp}/bst-cmark.$$ ( tr -c '\40-\176\n' ' ' < "$lib" > "$flat" 2>/dev/null ) # Nineteen members, one per upstream translation unit. Named rather than counted, # so a dropped or renamed member is identified by the failure. for m in blocks buffer cmark cmark_ctype commonmark houdini_href_e \ houdini_html_e houdini_html_u html inlines iterator latex man node \ references render scanners utf8 xml; do check "cmark/member-$m" grep -q "$m\.c\.o" "$flat" done # The whole public API: every one of the 69 cmark_* functions cmark.h declares. # The header/archive cross-check is exact -- there is no declared-but-undefined # name -- so a consumer that compiles against this header links against this # archive, which is the deliverable. for s in cmark_consolidate_text_nodes cmark_get_default_mem_allocator \ cmark_iter_free cmark_iter_get_event_type cmark_iter_get_node \ cmark_iter_get_root cmark_iter_new cmark_iter_next cmark_iter_reset \ cmark_markdown_to_html cmark_node_append_child cmark_node_first_child \ cmark_node_free cmark_node_get_end_column cmark_node_get_end_line \ cmark_node_get_fence_info cmark_node_get_heading_level \ cmark_node_get_list_delim cmark_node_get_list_start \ cmark_node_get_list_tight cmark_node_get_list_type \ cmark_node_get_literal cmark_node_get_on_enter cmark_node_get_on_exit \ cmark_node_get_start_column cmark_node_get_start_line \ cmark_node_get_title cmark_node_get_type cmark_node_get_type_string \ cmark_node_get_url cmark_node_get_user_data cmark_node_insert_after \ cmark_node_insert_before cmark_node_last_child cmark_node_new \ cmark_node_new_with_mem cmark_node_next cmark_node_parent \ cmark_node_prepend_child cmark_node_previous cmark_node_replace \ cmark_node_set_fence_info cmark_node_set_heading_level \ cmark_node_set_list_delim cmark_node_set_list_start \ cmark_node_set_list_tight cmark_node_set_list_type \ cmark_node_set_literal cmark_node_set_on_enter cmark_node_set_on_exit \ cmark_node_set_title cmark_node_set_url cmark_node_set_user_data \ cmark_node_unlink cmark_parse_document cmark_parse_file \ cmark_parser_feed cmark_parser_finish cmark_parser_free \ cmark_parser_new cmark_parser_new_with_mem \ cmark_parser_new_with_mem_into_root cmark_render_commonmark \ cmark_render_html cmark_render_latex cmark_render_man \ cmark_render_xml cmark_version cmark_version_string; do check "cmark/sym-$s" grep -q "$s" "$flat" done # The six houdini_* escapers. They are the HTML/URL escaping layer, exported but # undeclared in the public header -- present because html.c and xml.c call them # across translation units, and asserted so a visibility change that dropped them # shows up here rather than as a link error in a consumer. for s in houdini_escape_href houdini_escape_html houdini_escape_html0 \ houdini_unescape_ent houdini_unescape_html houdini_unescape_html_f; do check "cmark/houdini-$s" grep -q "$s" "$flat" done # The re2c-generated scanners. These are the lexer and the only generated C in the # build: scanners.c is checked in upstream, so re2c is NOT a build dependency here # -- which is why this recipe needed no native tool and no DEPENDS. for s in _scan_atx_heading_start _scan_setext_heading_line _scan_open_code_fence \ _scan_close_code_fence _scan_entity _scan_autolink_uri \ _scan_autolink_email _scan_html_tag _scan_dangerous_url _scan_scheme; do check "cmark/scanner-$s" grep -q "$s" "$flat" done # The allocator indirection every node goes through. check cmark/mem-default-allocator grep -q 'DEFAULT_MEM_ALLOCATOR' "$flat" # utf8proc is vendored inside cmark rather than linked, so these are the proof # UTF-8 handling is self-contained -- no libunistring, no ICU. for s in cmark_utf8proc_iterate cmark_utf8proc_encode_char cmark_utf8proc_check \ cmark_utf8proc_case_fold; do check "cmark/utf8proc-$s" grep -q "$s" "$flat" done # The wasm32 arm witness: the archive members are not host ELF. check cmark/arm-not-elf sh -c '! head -c 512 "$1" | grep -q "ELF"' _ "$lib" # Size window. libcmark.a is ~1.6 MB here, dominated by the entity table in # houdini_html_u.c and the re2c scanners. # The window is a measurement of the ARCHIVE, so it is asserted only where the # archive is what shipped; a shared object's size is a different number nobody # has measured, and inventing a window for it would assert a guess. if [ "${lib%.a}" != "$lib" ]; then sz=$(wc -c < "$lib") check cmark/lib-size-window sh -c '[ "$1" -gt 900000 ] && [ "$1" -lt 3000000 ]' _ "$sz" else bst_skip cmark/lib-size-window "window measured on libcmark.a; this image ships $lib" fi rm -f "$flat" # ------------------------------------------------------- packaging policy ----- # The library's shape rather than its absence. Asserting no .so encoded the # distro-wide static premise BRINTOS-1740 retires one recipe at a time, and it # fails on the recipe that converted correctly -- BRINTOS-893's class, and the # same reasoning as the .pc cases above. What survives conversion is that whatever # shipped is usable. bst_lib_shape cmark/no-so "$root/usr/lib/libcmark.so" "$root/usr/lib/libcmark.so.*" check cmark/no-la sh -c '! ls "$1"/libcmark.la >/dev/null 2>&1' _ "$root/usr/lib" # BUILD_TESTING=OFF: neither test binary is built, so neither can be installed. check cmark/no-api-test sh -c '! test -e "$1/usr/bin/api_test"' _ "$root" check cmark/no-spec-test sh -c '! test -e "$1/usr/bin/spec_tests"' _ "$root" # cmark-doc is deliberately not in the image, like every other port's -doc. check cmark/no-man1 sh -c '! test -e "$1/usr/share/man/man1/cmark.1"' _ "$root" check cmark/no-man3 sh -c '! test -e "$1/usr/share/man/man3/cmark.3"' _ "$root" # ------------------------------------------------------------- pkgconf -------- if command -v pkgconf >/dev/null 2>&1; then pcdir=$root/usr/lib/pkgconfig check_eq cmark/pkgconf-modversion "0.31.0" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --modversion libcmark 2>&1)" # Note 2. The filtered pair, then the restoring pair -- it is the SECOND of each # that carries the information, because empty filtered output alone is equally # consistent with a field that was never populated (which is what 76-libmxml # actually has). check_eq cmark/pkgconf-libs "-lcmark" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --libs libcmark 2>&1)" check_eq cmark/pkgconf-libs-keep "-L/usr/lib -lcmark" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --keep-system-libs --libs libcmark 2>&1)" check_eq cmark/pkgconf-cflags "" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --cflags libcmark 2>&1)" check_eq cmark/pkgconf-cflags-keep "-I/usr/include" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --keep-system-cflags --cflags libcmark 2>&1)" check_eq cmark/pkgconf-var-prefix "/usr" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --variable=prefix libcmark 2>&1)" check_eq cmark/pkgconf-var-libdir "/usr/lib" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --variable=libdir libcmark 2>&1)" check_eq cmark/pkgconf-var-includedir "/usr/include" \ "$(PKG_CONFIG_LIBDIR=$pcdir pkgconf --variable=includedir libcmark 2>&1)" check cmark/pkgconf-exists env PKG_CONFIG_LIBDIR=$pcdir pkgconf --exists libcmark check cmark/pkgconf-atleast env PKG_CONFIG_LIBDIR=$pcdir pkgconf --atleast-version=0.31.0 libcmark check_rc cmark/pkgconf-max 1 env PKG_CONFIG_LIBDIR=$pcdir pkgconf --max-version=0.30.0 libcmark # The module is libcmark, not cmark -- the .pc is named for the library, not the # recipe, and a consumer that guesses the recipe name gets nothing. check_rc cmark/pkgconf-not-cmark 1 env PKG_CONFIG_LIBDIR=$pcdir pkgconf --exists cmark else bst_skip cmark/pkgconf-present "pkgconf not on this image" fi # ------------------------------------------------------------- runtime -------- # Everything above this line is true of a payload that never ran. Below, the # parser runs. Expectations are the output of a native build of this same source # at this same SRCREV, so a difference here is a difference between this arm and # an ordinary host -- which is exactly what the suite is for. if command -v cmark >/dev/null 2>&1; then # %b so multi-line documents can be written inline; cmark reads stdin with no # arguments, which is the invocation every case below uses except file-arg. cm() { _md=$1; shift; printf '%b' "$_md" | cmark "$@"; } check_out cmark/run-version "cmark 0.31.0 - CommonMark converter" cmark --version check_out cmark/run-version-c "(C) 2014-2016 John MacFarlane" cmark --version check_out cmark/run-help "Usage: cmark [FILE*]" cmark --help check_out cmark/run-help-formats "html, xml, man, commonmark, latex" cmark --help # Leaf blocks. check_out cmark/run-atx-heading "

Hello

" cm '# Hello' check_out cmark/run-h2 "

Sub

" cm '## Sub' check_out cmark/run-setext "

Title

" cm 'Title\n=====' check_out cmark/run-thematic "
" cm '---' check_out cmark/run-paragraph "

plain

" cm 'plain' check_out cmark/run-indented-code "
code line" cm '    code line\n'
  check_out cmark/run-fenced-lang   '
int x;' cm '```c\nint x;\n```'

  # Inlines.
  check_out cmark/run-emphasis  "em"                     cm '*em*'
  check_out cmark/run-strong    "strong"         cm '**strong**'
  check_out cmark/run-nested-em "both"  cm '***both***'
  check_out cmark/run-codespan  "code"               cm 'a `code` b'
  check_out cmark/run-link      'text' cm '[text](http://example.com)'
  check_out cmark/run-image     'alt' cm '![alt](/img.png)'
  check_out cmark/run-autolink  'http://example.com' \
    cm ''
  # A backslash escape suppresses the emphasis and leaves the literal asterisks.
  check_out cmark/run-backslash "

*not em*

" cm '\\*not em\\*' # Containers. check_out cmark/run-blockquote "
" cm '> quoted' check_out cmark/run-ul "
  • one
  • " cm '- one\n- two' check_out cmark/run-ol "
  • first
  • " cm '1. first\n2. second' # A list that does not start at 1 carries the start attribute. check_out cmark/run-ol-start '
      ' cm '5. five\n6. six\n' # A blank line between items makes the list loose, which wraps each item in

      . check_out cmark/run-loose-list "$(printf '

    1. \n

      a

      ')" cm '- a\n\n- b\n' # Entities and escaping. & stays an entity; © is decoded to the # character. Both directions matter -- the first is escaping, the second is the # 2125-entry entity table in houdini_html_u.c doing its job. check_out cmark/run-entity-amp "AT&T" cm 'AT&T' check_out cmark/run-entity-copy "©" cm '©' # Note 1: raw HTML is filtered unless --unsafe. check_out cmark/run-html-filtered "" cm '
      raw
      ' check_out cmark/run-html-unsafe "
      raw
      " cm '
      raw
      ' --unsafe # Line-break handling, all three modes. A soft break survives as a real newline # inside the paragraph, so that needle has to be a real newline too. check_out cmark/run-softbreak "$(printf '

      a\nb

      ')" cm 'a\nb' check_out cmark/run-hardbreak "a
      " cm 'a \nb' check_out cmark/run-hardbreaks "a
      " cm 'a\nb' --hardbreaks check_out cmark/run-nobreaks "

      a b

      " cm 'a\nb' --nobreaks # --smart: straight quotes to curly, -- to en dash, ... to ellipsis. check_out cmark/run-smart-quote "“quoted”" cm '"quoted"' --smart check_out cmark/run-smart-dash "–" cm 'a -- b' --smart check_out cmark/run-smart-ellips "…" cm 'x...' --smart # UTF-8 passes through byte-identically; cmark is byte-oriented and vendors its # own utf8proc, so this exercises that vendored code rather than the locale. check_out cmark/run-utf8-latin1 "héllo" cm 'héllo' check_out cmark/run-utf8-emdash "—" cm '—' # --sourcepos annotates with 1-based line:col spans. check_out cmark/run-sourcepos 'data-sourcepos="1:1-1:4"' cm '# Hi' --sourcepos # The other four renderers. Each is a separate translation unit in the archive, # so these four cases are also the runtime counterpart of the member checks. check_out cmark/run-t-html "

      Hi

      " cm '# Hi' -t html check_out cmark/run-t-xml-doctype '' cm '# Hi' -t xml check_out cmark/run-t-xml-heading '' cm '# Hi' -t xml check_out cmark/run-t-latex '\section{Hi}' cm '# Hi' -t latex check_out cmark/run-t-man ".SH" cm '# Hi' -t man # commonmark out normalises the input rather than echoing it: three spaces after # the # collapse to one. check_out cmark/run-t-commonmark "# Hi" cm '# Hi' -t commonmark # Note 4: pipe tables are GFM, not CommonMark, so they stay a paragraph. check_out cmark/run-no-tables "

      | a | b |" cm '| a | b |\n| --- | --- |\n| 1 | 2 |' # File input, the one path that is not stdin -- and the one that touches the # target VFS rather than a pipe. doc=${TMPDIR:-/tmp}/bst-cmark-doc.$$ printf '# From a file\n\nBody *text*.\n' > "$doc" check_out cmark/run-file-heading "

      From a file

      " cmark "$doc" check_out cmark/run-file-body "Body text." cmark "$doc" rm -f "$doc" # Error paths: a missing file and an unknown option both exit 1, and the missing # file reports errno rather than failing silently. check_rc cmark/run-missing-file-rc 1 cmark "${TMPDIR:-/tmp}/bst-cmark-absent.$$" # The trailing `; true` is load-bearing: check_out requires rc 0, and this # command deliberately exits 1. The exit status is already asserted above, so # here only the diagnostic text is under test. check_out cmark/run-missing-file-msg "Error opening file" \ sh -c 'cmark "$1" 2>&1 >/dev/null; true' _ "${TMPDIR:-/tmp}/bst-cmark-absent.$$" check_out cmark/run-missing-file-errno "No such file or directory" \ sh -c 'cmark "$1" 2>&1 >/dev/null; true' _ "${TMPDIR:-/tmp}/bst-cmark-absent.$$" check_rc cmark/run-bad-option 1 sh -c 'printf x | cmark --nosuchopt' # Empty input is empty output and still a success -- the degenerate document. check_eq cmark/run-empty "" "$(printf '' | cmark 2>&1)" check_rc cmark/run-empty-rc 0 sh -c 'printf "" | cmark' else bst_skip cmark/run-present "cmark not on this image" fi