"Fossies" - the Fresh Open Source Software Archive

Member "asciidoctor-2.0.10/test/manpage_test.rb" (1 Jun 2019, 21750 Bytes) of package /linux/www/asciidoctor-2.0.10.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Ruby source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 # frozen_string_literal: true
    2 require_relative 'test_helper'
    3 
    4 context 'Manpage' do
    5   SAMPLE_MANPAGE_HEADER = <<~'EOS'.chop
    6   = command (1)
    7   Author Name
    8   :doctype: manpage
    9   :man manual: Command Manual
   10   :man source: Command 1.2.3
   11 
   12   == NAME
   13 
   14   command - does stuff
   15 
   16   == SYNOPSIS
   17 
   18   *command* [_OPTION_]... _FILE_...
   19 
   20   == DESCRIPTION
   21   EOS
   22 
   23   context 'Configuration' do
   24     test 'should set proper manpage-related attributes' do
   25       input = SAMPLE_MANPAGE_HEADER
   26       doc = Asciidoctor.load input, backend: :manpage
   27       assert_equal 'man', doc.attributes['filetype']
   28       assert_equal '', doc.attributes['filetype-man']
   29       assert_equal '1', doc.attributes['manvolnum']
   30       assert_equal '.1', doc.attributes['outfilesuffix']
   31       assert_equal 'command', doc.attributes['manname']
   32       assert_equal 'command', doc.attributes['mantitle']
   33       assert_equal 'does stuff', doc.attributes['manpurpose']
   34       assert_equal 'command', doc.attributes['docname']
   35     end
   36 
   37     test 'should output multiple mannames in NAME section' do
   38       input = SAMPLE_MANPAGE_HEADER.sub(/^command - /, 'command, alt_command - ')
   39       output = Asciidoctor.convert input, backend: :manpage, standalone: true
   40       assert_includes output.lines, %(command, alt_command \\- does stuff\n)
   41     end
   42 
   43     test 'should not parse NAME section if manname and manpurpose attributes are set' do
   44       input = <<~'EOS'
   45       = foobar (1)
   46       Author Name
   47       :doctype: manpage
   48       :man manual: Foo Bar Manual
   49       :man source: Foo Bar 1.0
   50 
   51       == SYNOPSIS
   52 
   53       *foobar* [_OPTIONS_]...
   54 
   55       == DESCRIPTION
   56 
   57       When you need to put some foo on the bar.
   58       EOS
   59 
   60       attrs = { 'manname' => 'foobar', 'manpurpose' => 'puts some foo on the bar' }
   61       doc = Asciidoctor.load input, backend: :manpage, standalone: true, attributes: attrs
   62       assert_equal 'foobar', (doc.attr 'manname')
   63       assert_equal ['foobar'], (doc.attr 'mannames')
   64       assert_equal 'puts some foo on the bar', (doc.attr 'manpurpose')
   65       assert_equal 'SYNOPSIS', doc.sections[0].title
   66     end
   67 
   68     test 'should normalize whitespace and skip line comments before and inside NAME section' do
   69       input = <<~'EOS'
   70       = foobar (1)
   71       Author Name
   72       :doctype: manpage
   73       :man manual: Foo Bar Manual
   74       :man source: Foo Bar 1.0
   75 
   76       // this is the name section
   77       == NAME
   78 
   79       // it follows the form `name - description`
   80       foobar - puts some foo
   81        on the bar
   82       // a little bit of this, a little bit of that
   83 
   84       == SYNOPSIS
   85 
   86       *foobar* [_OPTIONS_]...
   87 
   88       == DESCRIPTION
   89 
   90       When you need to put some foo on the bar.
   91       EOS
   92 
   93       doc = Asciidoctor.load input, backend: :manpage, standalone: true
   94       assert_equal 'puts some foo on the bar', (doc.attr 'manpurpose')
   95     end
   96 
   97     test 'should parse malformed document with warnings' do
   98       input = 'garbage in'
   99       using_memory_logger do |logger|
  100         doc = Asciidoctor.load input, backend: :manpage, standalone: true, attributes: { 'docname' => 'cmd' }
  101         assert_equal 'cmd', doc.attr('manname')
  102         assert_equal ['cmd'], doc.attr('mannames')
  103         assert_equal '.1', doc.attr('outfilesuffix')
  104         output = doc.convert
  105         refute logger.messages.empty?
  106         assert_includes output, 'Title: cmd'
  107         assert output.end_with?('garbage in')
  108       end
  109     end
  110 
  111     test 'should warn if document title is non-conforming' do
  112       input = <<~'EOS'
  113       = command
  114 
  115       == Name
  116 
  117       command - does stuff
  118       EOS
  119 
  120       using_memory_logger do |logger|
  121         document_from_string input, backend: :manpage
  122         assert_message logger, :ERROR, '<stdin>: line 1: non-conforming manpage title', Hash
  123       end
  124     end
  125 
  126     test 'should warn if first section is not name section' do
  127       input = <<~'EOS'
  128       = command(1)
  129 
  130       == Synopsis
  131 
  132       Does stuff.
  133       EOS
  134 
  135       using_memory_logger do |logger|
  136         doc = document_from_string input, backend: :manpage
  137         assert_message logger, :ERROR, '<stdin>: line 3: non-conforming name section body', Hash
  138         refute_nil doc.sections[0]
  139         assert_equal 'Synopsis', doc.sections[0].title
  140       end
  141     end
  142 
  143     test 'should define default linkstyle' do
  144       input = SAMPLE_MANPAGE_HEADER
  145       output = Asciidoctor.convert input, backend: :manpage, standalone: true
  146       assert_includes output.lines, %(.  LINKSTYLE blue R < >\n)
  147     end
  148 
  149     test 'should use linkstyle defined by man-linkstyle attribute' do
  150       input = SAMPLE_MANPAGE_HEADER
  151       output = Asciidoctor.convert input, backend: :manpage, standalone: true, attributes: { 'man-linkstyle' => 'cyan B \[fo] \[fc]' }
  152       assert_includes output.lines, %(.  LINKSTYLE cyan B \\[fo] \\[fc]\n)
  153     end
  154 
  155     test 'should require specialchars in value of man-linkstyle attribute defined in document to be escaped' do
  156       input = <<~EOS.chop
  157       :man-linkstyle: cyan R < >
  158       #{SAMPLE_MANPAGE_HEADER}
  159       EOS
  160       output = Asciidoctor.convert input, backend: :manpage, standalone: true
  161       assert_includes output.lines, %(.  LINKSTYLE cyan R &lt; &gt;\n)
  162 
  163       input = <<~EOS.chop
  164       :man-linkstyle: pass:[cyan R < >]
  165       #{SAMPLE_MANPAGE_HEADER}
  166       EOS
  167       output = Asciidoctor.convert input, backend: :manpage, standalone: true
  168       assert_includes output.lines, %(.  LINKSTYLE cyan R < >\n)
  169     end
  170   end
  171 
  172   context 'Manify' do
  173     test 'should unescape literal ampersand' do
  174       input = <<~EOS.chop
  175       #{SAMPLE_MANPAGE_HEADER}
  176 
  177       (C) & (R) are translated to character references, but not the &.
  178       EOS
  179       output = Asciidoctor.convert input, backend: :manpage
  180       assert_equal '\\(co & \\(rg are translated to character references, but not the &.', output.lines.last.chomp
  181     end
  182 
  183     test 'should replace em dashes' do
  184       input = <<~EOS.chop
  185       #{SAMPLE_MANPAGE_HEADER}
  186 
  187       go -- to
  188 
  189       go--to
  190       EOS
  191       output = Asciidoctor.convert input, backend: :manpage
  192       assert_includes output, 'go \\(em to'
  193       assert_includes output, 'go\\(emto'
  194     end
  195 
  196     test 'should escape lone period' do
  197       input = <<~EOS.chop
  198       #{SAMPLE_MANPAGE_HEADER}
  199 
  200       .
  201       EOS
  202       output = Asciidoctor.convert input, backend: :manpage
  203       assert_equal '\&.', output.lines.last.chomp
  204     end
  205 
  206     test 'should escape raw macro' do
  207       input = <<~EOS.chop
  208       #{SAMPLE_MANPAGE_HEADER}
  209 
  210       AAA this line of text should be show
  211       .if 1 .nx
  212       BBB this line and the one above it should be visible
  213       EOS
  214 
  215       output = Asciidoctor.convert input, backend: :manpage
  216       assert_equal '\&.if 1 .nx', output.lines[-2].chomp
  217     end
  218 
  219     test 'should normalize whitespace in a paragraph' do
  220       input = <<~EOS.chop
  221       #{SAMPLE_MANPAGE_HEADER}
  222 
  223       Oh, here it goes again
  224         I should have known,
  225           should have known,
  226       should have known again
  227       EOS
  228 
  229       output = Asciidoctor.convert input, backend: :manpage
  230       assert_includes output, %(Oh, here it goes again\nI should have known,\nshould have known,\nshould have known again)
  231     end
  232 
  233     test 'should normalize whitespace in a list item' do
  234       input = <<~EOS.chop
  235       #{SAMPLE_MANPAGE_HEADER}
  236 
  237       * Oh, here it goes again
  238           I should have known,
  239         should have known,
  240       should have known again
  241       EOS
  242 
  243       output = Asciidoctor.convert input, backend: :manpage
  244       assert_includes output, %(Oh, here it goes again\nI should have known,\nshould have known,\nshould have known again)
  245     end
  246 
  247     test 'should collapse whitespace in the man manual and man source' do
  248       input = <<~EOS.chop
  249       #{SAMPLE_MANPAGE_HEADER}
  250 
  251       Describe this thing.
  252       EOS
  253 
  254       output = Asciidoctor.convert input, backend: :manpage, standalone: true, attributes: {
  255         'manmanual' => %(General\nCommands\nManual),
  256         'mansource' => %(Control\nAll\nThe\nThings\n5.0),
  257       }
  258       assert_includes output, 'Manual: General Commands Manual'
  259       assert_includes output, 'Source: Control All The Things 5.0'
  260       assert_includes output, '"Control All The Things 5.0" "General Commands Manual"'
  261     end
  262   end
  263 
  264   context 'Backslash' do
  265     test 'should not escape spaces for empty manual or source fields' do
  266       input = SAMPLE_MANPAGE_HEADER.lines.select {|l| !l.start_with?(':man ') }
  267       output = Asciidoctor.convert input, backend: :manpage, standalone: true
  268       assert_match ' Manual: \ \&', output
  269       assert_match ' Source: \ \&', output
  270       assert_match(/^\.TH "COMMAND" .* "\\ \\&" "\\ \\&"$/, output)
  271     end
  272 
  273     test 'should preserve backslashes in escape sequences' do
  274       input = <<~EOS.chop
  275       #{SAMPLE_MANPAGE_HEADER}
  276 
  277       "`hello`" '`goodbye`' *strong* _weak_ `even`
  278       EOS
  279       output = Asciidoctor.convert input, backend: :manpage
  280       assert_equal '\(lqhello\(rq \(oqgoodbye\(cq \fBstrong\fP \fIweak\fP \f(CReven\fP', output.lines.last.chomp
  281     end
  282 
  283     test 'should escape backslashes in content' do
  284       input = <<~EOS.chop
  285       #{SAMPLE_MANPAGE_HEADER}
  286 
  287       \\.foo \\ bar\\
  288       baz
  289       EOS
  290       output = Asciidoctor.convert input, backend: :manpage
  291       assert_equal '\(rs.foo \(rs bar\(rs', output.lines[-2].chomp
  292     end
  293 
  294     test 'should escape literal escape sequence' do
  295       input = <<~EOS.chop
  296       #{SAMPLE_MANPAGE_HEADER}
  297 
  298        \\fB makes text bold
  299       EOS
  300       output = Asciidoctor.convert input, backend: :manpage
  301       assert_match '\(rsfB makes text bold', output
  302     end
  303 
  304     test 'should preserve inline breaks' do
  305       input = <<~EOS.chop
  306       #{SAMPLE_MANPAGE_HEADER}
  307 
  308       Before break. +
  309       After break.
  310       EOS
  311       expected = <<~'EOS'.chop
  312       Before break.
  313       .br
  314       After break.
  315       EOS
  316       output = Asciidoctor.convert input, backend: :manpage
  317       assert_equal expected, output.lines[-3..-1].join
  318     end
  319   end
  320 
  321   context 'URL macro' do
  322     test 'should not leave blank line before URL macro' do
  323       input = <<~EOS.chop
  324       #{SAMPLE_MANPAGE_HEADER}
  325       First paragraph.
  326 
  327       http://asciidoc.org[AsciiDoc]
  328       EOS
  329       expected = <<~'EOS'.chop
  330       .sp
  331       First paragraph.
  332       .sp
  333       .URL "http://asciidoc.org" "AsciiDoc" ""
  334       EOS
  335       output = Asciidoctor.convert input, backend: :manpage
  336       assert_equal expected, output.lines[-4..-1].join
  337     end
  338 
  339     test 'should not swallow content following URL' do
  340       input = <<~EOS.chop
  341       #{SAMPLE_MANPAGE_HEADER}
  342 
  343       http://asciidoc.org[AsciiDoc] can be used to create man pages.
  344       EOS
  345       expected = <<~'EOS'.chop
  346       .URL "http://asciidoc.org" "AsciiDoc" " "
  347       can be used to create man pages.
  348       EOS
  349       output = Asciidoctor.convert input, backend: :manpage
  350       assert_equal expected, output.lines[-2..-1].join
  351     end
  352 
  353     test 'should pass adjacent character as final argument of URL macro' do
  354       input = <<~EOS.chop
  355       #{SAMPLE_MANPAGE_HEADER}
  356 
  357       This is http://asciidoc.org[AsciiDoc].
  358       EOS
  359       expected = <<~'EOS'.chop
  360       This is \c
  361       .URL "http://asciidoc.org" "AsciiDoc" "."
  362       EOS
  363       output = Asciidoctor.convert input, backend: :manpage
  364       assert_equal expected, output.lines[-2..-1].join
  365     end
  366 
  367     test 'should pass adjacent character as final argument of URL macro and move trailing content to next line' do
  368       input = <<~EOS.chop
  369       #{SAMPLE_MANPAGE_HEADER}
  370 
  371       This is http://asciidoc.org[AsciiDoc], which can be used to write content.
  372       EOS
  373       expected = <<~'EOS'.chop
  374       This is \c
  375       .URL "http://asciidoc.org" "AsciiDoc" ","
  376       which can be used to write content.
  377       EOS
  378       output = Asciidoctor.convert input, backend: :manpage
  379       assert_equal expected, output.lines[-3..-1].join
  380     end
  381 
  382     test 'should not leave blank lines between URLs on contiguous lines of input' do
  383       input = <<~EOS.chop
  384       #{SAMPLE_MANPAGE_HEADER}
  385 
  386       The corresponding implementations are
  387       http://clisp.sf.net[CLISP],
  388       http://ccl.clozure.com[Clozure CL],
  389       http://cmucl.org[CMUCL],
  390       http://ecls.sf.net[ECL],
  391       and http://sbcl.sf.net[SBCL].
  392       EOS
  393       expected = <<~'EOS'.chop
  394       .sp
  395       The corresponding implementations are
  396       .URL "http://clisp.sf.net" "CLISP" ","
  397       .URL "http://ccl.clozure.com" "Clozure CL" ","
  398       .URL "http://cmucl.org" "CMUCL" ","
  399       .URL "http://ecls.sf.net" "ECL" ","
  400       and \c
  401       .URL "http://sbcl.sf.net" "SBCL" "."
  402       EOS
  403       output = Asciidoctor.convert input, backend: :manpage
  404       assert_equal expected, output.lines[-8..-1].join
  405     end
  406 
  407     test 'should not leave blank lines between URLs on same line of input' do
  408       input = <<~EOS.chop
  409       #{SAMPLE_MANPAGE_HEADER}
  410 
  411       The corresponding implementations are http://clisp.sf.net[CLISP], http://ccl.clozure.com[Clozure CL], http://cmucl.org[CMUCL], http://ecls.sf.net[ECL], and http://sbcl.sf.net[SBCL].
  412       EOS
  413       expected = <<~'EOS'.chop
  414       .sp
  415       The corresponding implementations are \c
  416       .URL "http://clisp.sf.net" "CLISP" ","
  417       .URL "http://ccl.clozure.com" "Clozure CL" ","
  418       .URL "http://cmucl.org" "CMUCL" ","
  419       .URL "http://ecls.sf.net" "ECL" ","
  420       and
  421       .URL "http://sbcl.sf.net" "SBCL" "."
  422       EOS
  423       output = Asciidoctor.convert input, backend: :manpage
  424       assert_equal expected, output.lines[-8..-1].join
  425     end
  426 
  427     test 'should not insert space between link and non-whitespace characters surrounding it' do
  428       input = <<~EOS.chop
  429       #{SAMPLE_MANPAGE_HEADER}
  430 
  431       Please search |link:http://discuss.asciidoctor.org[the forums]| before asking.
  432       EOS
  433       expected = <<~'EOS'.chop
  434       .sp
  435       Please search |\c
  436       .URL "http://discuss.asciidoctor.org" "the forums" "|"
  437       before asking.
  438       EOS
  439       output = Asciidoctor.convert input, backend: :manpage
  440       assert_equal expected, output.lines[-4..-1].join
  441     end
  442 
  443     test 'should be able to use monospaced text inside a link' do
  444       input = <<~EOS.chop
  445       #{SAMPLE_MANPAGE_HEADER}
  446 
  447       Enter the link:cat[`cat`] command.
  448       EOS
  449       expected = <<~'EOS'.chop
  450       .sp
  451       Enter the \c
  452       .URL "cat" "\f(CRcat\fP" " "
  453       command.
  454       EOS
  455       output = Asciidoctor.convert input, backend: :manpage
  456       assert_equal expected, output.lines[-4..-1].join
  457     end
  458   end
  459 
  460   context 'MTO macro' do
  461     test 'should convert inline email macro into MTO macro' do
  462       input = <<~EOS.chop
  463       #{SAMPLE_MANPAGE_HEADER}
  464       First paragraph.
  465 
  466       mailto:doc@example.org[Contact the doc]
  467       EOS
  468       expected = <<~'EOS'.chop
  469       .sp
  470       First paragraph.
  471       .sp
  472       .MTO "doc\(atexample.org" "Contact the doc" ""
  473       EOS
  474       output = Asciidoctor.convert input, backend: :manpage
  475       assert_equal expected, output.lines[-4..-1].join
  476     end
  477 
  478     test 'should set text of MTO macro to blank for implicit email' do
  479       input = <<~EOS.chop
  480       #{SAMPLE_MANPAGE_HEADER}
  481       Bugs fixed daily by doc@example.org.
  482       EOS
  483       expected_coda = <<~'EOS'.chop
  484       Bugs fixed daily by \c
  485       .MTO "doc\(atexample.org" "" "."
  486       EOS
  487       output = Asciidoctor.convert input, backend: :manpage
  488       assert output.end_with? expected_coda
  489     end
  490   end
  491 
  492   context 'Table' do
  493     test 'should create header, body, and footer rows in correct order' do
  494       input = <<~EOS.chop
  495       #{SAMPLE_MANPAGE_HEADER}
  496 
  497       [%header%footer]
  498       |===
  499       |Header
  500       |Body 1
  501       |Body 2
  502       |Footer
  503       |===
  504       EOS
  505       expected_coda = <<~'EOS'.chop
  506       allbox tab(:);
  507       lt.
  508       T{
  509       .sp
  510       Header
  511       T}
  512       T{
  513       .sp
  514       Body 1
  515       T}
  516       T{
  517       .sp
  518       Body 2
  519       T}
  520       T{
  521       .sp
  522       Footer
  523       T}
  524       .TE
  525       .sp
  526       EOS
  527       output = Asciidoctor.convert input, backend: :manpage
  528       assert output.end_with? expected_coda
  529     end
  530 
  531     test 'should manify normal table cell content' do
  532       input = <<~EOS.chop
  533       #{SAMPLE_MANPAGE_HEADER}
  534 
  535       |===
  536       |*Col A* |_Col B_
  537 
  538       |*bold* |`mono`
  539       |_italic_ | #mark#
  540       |===
  541       EOS
  542       output = Asciidoctor.convert input, backend: :manpage
  543       refute_match(/<\/?BOUNDARY>/, output)
  544     end
  545 
  546     test 'should manify table title' do
  547       input = <<~EOS.chop
  548       #{SAMPLE_MANPAGE_HEADER}
  549 
  550       .Table of options
  551       |===
  552       | Name | Description | Default
  553 
  554       | dim
  555       | dimension of the object
  556       | 3
  557       |===
  558       EOS
  559       expected_coda = <<~'EOS'.chop
  560       .it 1 an-trap
  561       .nr an-no-space-flag 1
  562       .nr an-break-flag 1
  563       .br
  564       .B Table 1. Table of options
  565       .TS
  566       allbox tab(:);
  567       lt lt lt.
  568       T{
  569       .sp
  570       Name
  571       T}:T{
  572       .sp
  573       Description
  574       T}:T{
  575       .sp
  576       Default
  577       T}
  578       T{
  579       .sp
  580       dim
  581       T}:T{
  582       .sp
  583       dimension of the object
  584       T}:T{
  585       .sp
  586       3
  587       T}
  588       .TE
  589       .sp
  590       EOS
  591       output = Asciidoctor.convert input, backend: :manpage
  592       assert output.end_with? expected_coda
  593     end
  594 
  595     test 'should manify and preserve whitespace in literal table cell' do
  596       input = <<~EOS.chop
  597       #{SAMPLE_MANPAGE_HEADER}
  598 
  599       |===
  600       |a l|b
  601       c    _d_
  602       .
  603       |===
  604       EOS
  605       expected_coda = <<~'EOS'.chop
  606       .TS
  607       allbox tab(:);
  608       lt lt.
  609       T{
  610       .sp
  611       a
  612       T}:T{
  613       .sp
  614       .nf
  615       b
  616       c    _d_
  617       \&.
  618       .fi
  619       T}
  620       .TE
  621       .sp
  622       EOS
  623       output = Asciidoctor.convert input, backend: :manpage
  624       assert output.end_with? expected_coda
  625     end
  626   end
  627 
  628   context 'Images' do
  629     test 'should replace block image with alt text enclosed in square brackets' do
  630       input = <<~EOS.chop
  631       #{SAMPLE_MANPAGE_HEADER}
  632 
  633       Behold the wisdom of the Magic 8 Ball!
  634 
  635       image::signs-point-to-yes.jpg[]
  636       EOS
  637 
  638       output = Asciidoctor.convert input, backend: :manpage
  639       assert output.end_with? %(\n.sp\n[signs point to yes])
  640     end
  641 
  642     test 'should replace inline image with alt text enclosed in square brackets' do
  643       input = <<~EOS.chop
  644       #{SAMPLE_MANPAGE_HEADER}
  645 
  646       The Magic 8 Ball says image:signs-point-to-yes.jpg[].
  647       EOS
  648       output = Asciidoctor.convert input, backend: :manpage
  649       assert_includes output, 'The Magic 8 Ball says [signs point to yes].'
  650     end
  651 
  652     test 'should place link after alt text for inline image if link is defined' do
  653       input = <<~EOS.chop
  654       #{SAMPLE_MANPAGE_HEADER}
  655 
  656       The Magic 8 Ball says image:signs-point-to-yes.jpg[link=https://en.wikipedia.org/wiki/Magic_8-Ball].
  657       EOS
  658       output = Asciidoctor.convert input, backend: :manpage
  659       assert_includes output, 'The Magic 8 Ball says [signs point to yes] <https://en.wikipedia.org/wiki/Magic_8\-Ball>.'
  660     end
  661 
  662     test 'should reference image with title usign styled xref' do
  663       input = <<~EOS.chomp
  664       #{SAMPLE_MANPAGE_HEADER}
  665 
  666       To get your fortune, see <<magic-8-ball>>.
  667 
  668       .Magic 8-Ball
  669       [#magic-8-ball]
  670       image::signs-point-to-yes.jpg[]
  671       EOS
  672       output = Asciidoctor.convert input, backend: :manpage, attributes: { 'xrefstyle' => 'full' }
  673       lines = output.lines.map(&:chomp)
  674       assert_includes lines, 'To get your fortune, see Figure 1, \(lqMagic 8\-Ball\(rq.'
  675       assert_includes lines, '.B Figure 1. Magic 8\-Ball'
  676     end
  677   end
  678 
  679   context 'Quote Block' do
  680     test 'should indent quote block' do
  681       input = <<~EOS.chop
  682       #{SAMPLE_MANPAGE_HEADER}
  683 
  684       [,James Baldwin]
  685       ____
  686       Not everything that is faced can be changed.
  687       But nothing can be changed until it is faced.
  688       ____
  689       EOS
  690       expected_coda = <<~'EOS'.chop
  691       .RS 3
  692       .ll -.6i
  693       .sp
  694       Not everything that is faced can be changed.
  695       But nothing can be changed until it is faced.
  696       .br
  697       .RE
  698       .ll
  699       .RS 5
  700       .ll -.10i
  701       \(em James Baldwin
  702       .RE
  703       .ll
  704       EOS
  705       output = Asciidoctor.convert input, backend: :manpage
  706       assert output.end_with? expected_coda
  707     end
  708   end
  709 
  710   context 'Callout List' do
  711     test 'should generate callout list using proper formatting commands' do
  712       input = <<~EOS.chop
  713       #{SAMPLE_MANPAGE_HEADER}
  714 
  715       ----
  716       $ gem install asciidoctor # <1>
  717       ----
  718       <1> Installs the asciidoctor gem from RubyGems.org
  719       EOS
  720       expected_coda = <<~'EOS'.chop
  721       .TS
  722       tab(:);
  723       r lw(\n(.lu*75u/100u).
  724       \fB(1)\fP\h'-2n':T{
  725       Installs the asciidoctor gem from RubyGems.org
  726       T}
  727       .TE
  728       EOS
  729       output = Asciidoctor.convert input, backend: :manpage
  730       assert output.end_with? expected_coda
  731     end
  732   end
  733 
  734   context 'Environment' do
  735     test 'should use SOURCE_DATE_EPOCH as modified time of input file and local time' do
  736       old_source_date_epoch = ENV.delete 'SOURCE_DATE_EPOCH'
  737       begin
  738         ENV['SOURCE_DATE_EPOCH'] = '1234123412'
  739         output = Asciidoctor.convert SAMPLE_MANPAGE_HEADER, backend: :manpage, standalone: true
  740         assert_match(/Date: 2009-02-08/, output)
  741         assert_match(/^\.TH "COMMAND" "1" "2009-02-08" "Command 1.2.3" "Command Manual"$/, output)
  742       ensure
  743         if old_source_date_epoch
  744           ENV['SOURCE_DATE_EPOCH'] = old_source_date_epoch
  745         else
  746           ENV.delete 'SOURCE_DATE_EPOCH'
  747         end
  748       end
  749     end
  750 
  751     test 'should fail if SOURCE_DATE_EPOCH is malformed' do
  752       old_source_date_epoch = ENV.delete 'SOURCE_DATE_EPOCH'
  753       begin
  754         ENV['SOURCE_DATE_EPOCH'] = 'aaaaaaaa'
  755         Asciidoctor.convert SAMPLE_MANPAGE_HEADER, backend: :manpage, standalone: true
  756         assert false
  757       rescue
  758         assert true
  759       ensure
  760         if old_source_date_epoch
  761           ENV['SOURCE_DATE_EPOCH'] = old_source_date_epoch
  762         else
  763           ENV.delete 'SOURCE_DATE_EPOCH'
  764         end
  765       end
  766     end
  767   end
  768 end