# encoding: UTF-8
unless defined? ASCIIDOCTOR_PROJECT_DIR
  $: << File.dirname(__FILE__); $:.uniq!
  require 'test_helper'
end

SAMPLE_MANPAGE_HEADER = <<-EOS.chomp
= command (1)
Author Name
:doctype: manpage
:man manual: Command Manual
:man source: Command 1.2.3

== NAME

command - does stuff

== SYNOPSIS

*command* [_OPTION_]... _FILE_...

== DESCRIPTION
EOS

context 'Manpage' do
  context 'Configuration' do
    test 'should set proper manpage-related attributes' do
      input = SAMPLE_MANPAGE_HEADER
      doc = Asciidoctor.load input, :backend => :manpage
      assert_equal 'man', doc.attributes['filetype']
      assert_equal '', doc.attributes['filetype-man']
      assert_equal '1', doc.attributes['manvolnum']
      assert_equal '.1', doc.attributes['outfilesuffix']
      assert_equal 'command', doc.attributes['manname']
      assert_equal 'command', doc.attributes['mantitle']
      assert_equal 'does stuff', doc.attributes['manpurpose']
      assert_equal 'command', doc.attributes['docname']
    end

    test 'should define default linkstyle' do
      input = SAMPLE_MANPAGE_HEADER
      output = Asciidoctor.convert input, :backend => :manpage, :header_footer => true
      assert_includes output.lines, %(.LINKSTYLE blue R < >\n)
    end

    test 'should use linkstyle defined by man-linkstyle attribute' do
      input = SAMPLE_MANPAGE_HEADER
      output = Asciidoctor.convert input, :backend => :manpage, :header_footer => true,
          :attributes => { 'man-linkstyle' => 'cyan B \[fo] \[fc]' }
      assert_includes output.lines, %(.LINKSTYLE cyan B \\[fo] \\[fc]\n)
    end

    test 'should require specialchars in value of man-linkstyle attribute defined in document to be escaped' do
      input = %(:man-linkstyle: cyan R < >
#{SAMPLE_MANPAGE_HEADER})
      output = Asciidoctor.convert input, :backend => :manpage, :header_footer => true
      assert_includes output.lines, %(.LINKSTYLE cyan R &lt; &gt;\n)

      input = %(:man-linkstyle: pass:[cyan R < >]
#{SAMPLE_MANPAGE_HEADER})
      output = Asciidoctor.convert input, :backend => :manpage, :header_footer => true
      assert_includes output.lines, %(.LINKSTYLE cyan R < >\n)
    end
  end

  context 'Manify' do
    test 'should escape lone period' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

.)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '\&.', output.lines.entries.last.chomp
    end

    test 'should escape raw macro' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

AAA this line of text should be show
.if 1 .nx
BBB this line and the one above it should be visible)

      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '\&.if 1 .nx', output.lines.entries[-2].chomp
    end
  end

  context 'Backslash' do
    test 'should not escape spaces for empty manual or source fields' do
      input = SAMPLE_MANPAGE_HEADER.lines.select {|l| !l.start_with?(':man ') }
      output = Asciidoctor.convert input, :backend => :manpage, :header_footer => true
      assert_match ' Manual: \ \&', output
      assert_match ' Source: \ \&', output
      assert_match(/^\.TH "COMMAND" .* "\\ \\&" "\\ \\&"$/, output)
    end

    test 'should preserve backslashes in escape sequences' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

"`hello`" '`goodbye`' *strong* _weak_ `even`)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '\(lqhello\(rq \(oqgoodbye\(cq \fBstrong\fP \fIweak\fP \f[CR]even\fP', output.lines.entries.last.chomp
    end

    test 'should escape backslashes in content' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

\\.foo \\ bar\\
baz)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '\(rs.foo \(rs bar\(rs', output.lines.entries[-2].chomp
    end

    test 'should escape literal escape sequence' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

 \\fB makes text bold)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_match '\(rsfB makes text bold', output
    end

    test 'should preserve inline breaks' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

Before break. +
After break.)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal 'Before break.
.br
After break.', output.lines.entries[-3..-1].join
    end
  end

  context 'URL macro' do
    test 'should not leave blank line before URL macro' do
      input = %(#{SAMPLE_MANPAGE_HEADER}
First paragraph.

http://asciidoc.org[AsciiDoc])
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '.sp
First paragraph.
.sp
.URL "http://asciidoc.org" "AsciiDoc" ""', output.lines.entries[-4..-1].join
    end

    test 'should not swallow content following URL' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

http://asciidoc.org[AsciiDoc] can be used to create man pages.)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '.URL "http://asciidoc.org" "AsciiDoc" " "
can be used to create man pages.', output.lines.entries[-2..-1].join
    end

    test 'should pass adjacent character as final argument of URL macro' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

This is http://asciidoc.org[AsciiDoc].)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal 'This is \c
.URL "http://asciidoc.org" "AsciiDoc" "."', output.lines.entries[-2..-1].join
    end

    test 'should pass adjacent character as final argument of URL macro and move trailing content to next line' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

This is http://asciidoc.org[AsciiDoc], which can be used to write content.)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal 'This is \c
.URL "http://asciidoc.org" "AsciiDoc" ","
which can be used to write content.', output.lines.entries[-3..-1].join
    end

    test 'should not leave blank lines between URLs on contiguous lines of input' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

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].)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '.sp
The corresponding implementations are
.URL "http://clisp.sf.net" "CLISP" ","
.URL "http://ccl.clozure.com" "Clozure CL" ","
.URL "http://cmucl.org" "CMUCL" ","
.URL "http://ecls.sf.net" "ECL" ","
and \c
.URL "http://sbcl.sf.net" "SBCL" "."', output.lines.entries[-8..-1].join
    end

    test 'should not leave blank lines between URLs on same line of input' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

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].)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '.sp
The corresponding implementations are \c
.URL "http://clisp.sf.net" "CLISP" ","
.URL "http://ccl.clozure.com" "Clozure CL" ","
.URL "http://cmucl.org" "CMUCL" ","
.URL "http://ecls.sf.net" "ECL" ","
and
.URL "http://sbcl.sf.net" "SBCL" "."', output.lines.entries[-8..-1].join
    end

    test 'should not insert space between link and non-whitespace characters surrounding it' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

Please search |link:http://discuss.asciidoctor.org[the forums]| before asking.)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_equal '.sp
Please search |\c
.URL "http://discuss.asciidoctor.org" "the forums" "|"
before asking.', output.lines.entries[-4..-1].join
    end
  end

  context 'Table' do
    test 'should manify normal table cell content' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

[%header%footer,cols=2*]
|===
|*Col A* |_Col B_
|*bold* |`mono`
|_italic_ | #mark#
|===)
      output = Asciidoctor.convert input, :backend => :manpage
      refute_match(/<\/?BOUNDARY>/, output)
    end

    test 'should manify table title' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

.Table of options
|===
| Name | Description | Default

| dim
| dimension of the object
| 3
|===)
      output = Asciidoctor.convert input, :backend => :manpage
      assert output.end_with? '.it 1 an-trap
.nr an-no-space-flag 1
.nr an-break-flag 1
.br
.B Table 1. Table of options
.TS
allbox tab(:);
lt lt lt.
T{
.sp
Name
T}:T{
.sp
Description
T}:T{
.sp
Default
T}
T{
.sp
dim
T}:T{
.sp
dimension of the object
T}:T{
.sp
3
T}
.TE
.sp'
    end

    test 'should manify and preserve whitespace in literal table cell' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

|===
|a l|b
c    _d_
.
|===)
      output = Asciidoctor.convert input, :backend => :manpage
      assert output.end_with? '.TS
allbox tab(:);
lt lt.
T{
.sp
a
T}:T{
.sp
.nf
b
c    _d_
\\&.
.fi
T}
.TE
.sp'
    end

    test 'should manify and preserve whitespace in verse table cell' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

|===
|a v|b
c    _d_
.
|===)
      output = Asciidoctor.convert input, :backend => :manpage
      assert output.end_with? '.TS
allbox tab(:);
lt lt.
T{
.sp
a
T}:T{
.sp
.nf
b
c    \\fId\\fP
\\&.
.fi
T}
.TE
.sp'
    end
  end

  context 'Images' do
    test 'should replace inline image with alt text' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

The Magic 8 Ball says image:signs-point-to-yes.jpg[].)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_includes output, 'The Magic 8 Ball says [signs point to yes].'
    end

    test 'should place link after alt text for inline image if link is defined' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

The Magic 8 Ball says image:signs-point-to-yes.jpg[link=https://en.wikipedia.org/wiki/Magic_8-Ball].)
      output = Asciidoctor.convert input, :backend => :manpage
      assert_includes output, 'The Magic 8 Ball says [signs point to yes] <https://en.wikipedia.org/wiki/Magic_8\-Ball>.'
    end
  end

  context 'Callout List' do
    test 'should generate callout list using proper formatting commands' do
      input = %(#{SAMPLE_MANPAGE_HEADER}

----
$ gem install asciidoctor # <1>
----
<1> Installs the asciidoctor gem from RubyGems.org)
      output = Asciidoctor.convert input, :backend => :manpage
      assert output.end_with? '.TS
tab(:);
r lw(\n(.lu*75u/100u).
\fB(1)\fP\h\'-2n\':T{
Installs the asciidoctor gem from RubyGems.org
T}
.TE'
    end
  end

  context 'Environment' do
    test 'should use SOURCE_DATE_EPOCH as modified time of input file and local time' do
      old_source_date_epoch = ENV.delete 'SOURCE_DATE_EPOCH'
      begin
        ENV['SOURCE_DATE_EPOCH'] = '1234123412'
        output = Asciidoctor.convert SAMPLE_MANPAGE_HEADER, :backend => :manpage, :header_footer => true
        assert_match(/Date: 2009-02-08/, output)
        assert_match(/^\.TH "COMMAND" "1" "2009-02-08" "Command 1.2.3" "Command Manual"$/, output)
      ensure
        if old_source_date_epoch
          ENV['SOURCE_DATE_EPOCH'] = old_source_date_epoch
        else
          ENV.delete 'SOURCE_DATE_EPOCH'
        end
      end
    end

    test 'should fail if SOURCE_DATE_EPOCH is malformed' do
      old_source_date_epoch = ENV.delete 'SOURCE_DATE_EPOCH'
      begin
        ENV['SOURCE_DATE_EPOCH'] = 'aaaaaaaa'
        Asciidoctor.convert SAMPLE_MANPAGE_HEADER, :backend => :manpage, :header_footer => true
        assert false
      rescue
        assert true
      ensure
        if old_source_date_epoch
          ENV['SOURCE_DATE_EPOCH'] = old_source_date_epoch
        else
          ENV.delete 'SOURCE_DATE_EPOCH'
        end
      end
    end
  end
end
