~shulhan/asciidoctor-go

9fe1ecf6050bbebfe4096e5c41a1e711dd16190d — Shulhan 2 years ago 502ccd5
all: rewrite unit tests for inlineParser using test.Data

Using string literal for testing string input that may contains backtick
or double quote make the test code become unreadable and hard to modify.

The test.Data help this by moving the input and expected output into
a file that can we write as is.
4 files changed, 294 insertions(+), 787 deletions(-)

M element.go
M inline_parser.go
M inline_parser_test.go
A testdata/inline_parser/inline_parser_test.txt
M element.go => element.go +0 -14
@@ 256,20 256,6 @@ func (el *element) backTrimSpace() {
	el.raw = el.raw[:x+1]
}

func (el *element) debug(n int) {
	var x int
	for x = 0; x < n; x++ {
		fmt.Printf("\t")
	}
	fmt.Printf("el: {kind:%-3d style:%-3d raw:%s}\n", el.kind, el.style, el.raw)
	if el.child != nil {
		el.child.debug(n + 1)
	}
	if el.next != nil {
		el.next.debug(n)
	}
}

func (el *element) lastSuccessor() (last *element) {
	if el.child == nil {
		return nil

M inline_parser.go => inline_parser.go +5 -1
@@ 617,12 617,16 @@ func (pi *inlineParser) parseFormat(kind int, style int64) bool {

		el     *element
		idx    int
		prevc  byte
		nextc  byte
		hasEnd bool
	)

	_, idx = indexByteUnescape(raw, pi.c)
	for idx >= 0 {
		var prevc, nextc byte
		prevc = 0
		nextc = 0

		if idx > 0 {
			prevc = raw[idx-1]
		}

M inline_parser_test.go => inline_parser_test.go +42 -772
@@ 5,804 5,78 @@ package asciidoctor

import (
	"bytes"
	"fmt"
	"testing"

	"github.com/shuLhan/share/lib/debug"
	"github.com/shuLhan/share/lib/test"
)

func TestInlineParser_do(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: "*A _B `C_ D` E*",
		exp:     "<strong>A <em>B <code>C</code></em><code> D</code> E</strong>",
	}, {
		content: "A * B *, C *=*.",
		exp:     "A * B <strong>, C *=</strong>.",
	}, {
		content: "*A _B `C D* E_ F.",
		exp:     "<strong>A <em>B `C D</em></strong><em> E</em> F.",
	}}

func TestInlineParser(t *testing.T) {
	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)
	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseAttrRef(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		Attributes: map[string]string{
			`x`: `https://kilabit.info`,
		},
	}

	var cases = []testCase{{
		content: `A {x}[*B*] C`,
		exp:     `A <a href="https://kilabit.info"><strong>B</strong></a> C`,
	}, {
		content: `A {x }[*B*] C`,
		exp:     `A <a href="https://kilabit.info"><strong>B</strong></a> C`,
	}, {
		content: `A {x }*B* C`,
		exp:     `A <a href="https://kilabit.info*B*" class="bare">https://kilabit.info*B*</a> C`,
	}, {
		content: `A {y }*B* C`,
		exp:     `A {y }<strong>B</strong> C`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseCrossReference(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: map[string]*anchor{
			`x`: &anchor{
				label: `X y`,
		_testDoc = &Document{
			Attributes: map[string]string{
				`x`: `https://kilabit.info`,
			},
		},
		titleID: map[string]string{
			`X y`: `x`,
		},
	}

	var cases = []testCase{{
		content: `A <<x>>`,
		exp:     `A <a href="#x">X y</a>`,
	}, {
		content: `A <<x, Label>>`,
		exp:     `A <a href="#x">Label</a>`,
	}, {
		content: `A <<X y>>`,
		exp:     `A <a href="#x">X y</a>`,
	}, {
		content: `A <<X y,Label>>`,
		exp:     `A <a href="#x">Label</a>`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)
	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseFormat(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `_A_B`,
		exp:     `_A_B`,
	}, {
		content: `_A_ B`,
		exp:     `<em>A</em> B`,
	}, {
		content: `_A _B`,
		exp:     `_A _B`,
	}, {
		content: `*A*B`,
		exp:     `*A*B`,
	}, {
		content: `*A* B`,
		exp:     `<strong>A</strong> B`,
	}, {
		content: `*A *B`,
		exp:     `*A *B`,
	}, {
		content: "`A`B",
		exp:     "`A`B",
	}, {
		content: "`A` B",
		exp:     `<code>A</code> B`,
	}, {
		content: "`A `B",
		exp:     "`A `B",
	}, {
		content: "A `/**/` *B*",
		exp:     "A <code>/<strong></strong>/</code> <strong>B</strong>",
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseFormatUnconstrained(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `__A__B`,
		exp:     `<em>A</em>B`,
	}, {
		content: `__A *B*__`,
		exp:     `<em>A <strong>B</strong></em>`,
	}, {
		content: `__A _B_ C__`,
		exp:     `<em>A <em>B</em> C</em>`,
	}, {
		content: `__A B_ C__`,
		exp:     `<em>A B_ C</em>`,
	}, {
		content: `__A *B*_`,
		exp:     `<em>_A <strong>B</strong></em>`,
	}, {
		content: `_A *B*__`,
		exp:     `<em>A <strong>B</strong>_</em>`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseInlineID(t *testing.T) {
	type testCase struct {
		content  string
		exp      string
		isForToC bool
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `[[A]] B`,
		exp:     `<a id="A"></a> B`,
	}, {
		content:  `[[A]] B`,
		exp:      ` B`,
		isForToC: true,
	}, {
		content: `[[A] B`,
		exp:     `[[A] B`,
	}, {
		content: `[A]] B`,
		exp:     `[A]] B`,
	}, {
		content: `[[A ]] B`,
		exp:     `[[A ]] B`,
	}, {
		content: `[[ A]] B`,
		exp:     `[[ A]] B`,
	}, {
		content: `[[A B]] C`,
		exp:     `[[A B]] C`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		_testDoc.isForToC = c.isForToC
		container.toHTML(_testDoc, &buf)
		_testDoc.isForToC = false

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseInlineIDShort(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `[#A]#B#`,
		exp:     `<span id="A">B</span>`,
	}, {
		content: `[#A]#B`,
		exp:     `[#A]#B`,
	}, {
		content: `[#A]B#`,
		exp:     `[#A]B#`,
	}, {
		content: `[#A ]#B#`,
		exp:     `[#A ]#B#`,
	}, {
		content: `[# A]# B#`,
		exp:     `[# A]# B#`,
	}, {
		content: `[#A B]# C#`,
		exp:     `[#A B]# C#`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseInlineImage(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `image:https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg[Linux,25,35]`,
		exp:     `<span class="image"><img src="https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg" alt="Linux" width="25" height="35"></span>`,
	}, {
		content: `image:linux.png[Linux,150,150,float="right"]
You can find Linux everywhere these days!`,
		exp: `<span class="image right"><img src="linux.png" alt="Linux" width="150" height="150"></span>
You can find Linux everywhere these days!`,
	}, {
		content: `image:sunset.jpg[Sunset,150,150,role="right"] What a beautiful sunset!`,
		exp:     `<span class="image right"><img src="sunset.jpg" alt="Sunset" width="150" height="150"></span> What a beautiful sunset!`,
	}, {
		content: `image:sunset.jpg[Sunset]
image:linux.png[2]`,
		exp: `<span class="image"><img src="sunset.jpg" alt="Sunset"></span>
<span class="image"><img src="linux.png" alt="2"></span>`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parsePassthrough(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: "`+__A *B*__+`",
		exp:     "<code>__A *B*__</code>",
	}, {
		content: `\+__A *B*__+`,
		exp:     `+<em>A <strong>B</strong></em>+`,
	}, {
		content: `+__A *B*__\+`,
		exp:     `+<em>A <strong>B</strong></em>+`,
	}, {
		content: `X+__A *B*__+`,
		exp:     `X+<em>A <strong>B</strong></em>+`,
	}, {
		content: `+__A *B*__+X`,
		exp:     `+<em>A <strong>B</strong></em>+X`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parsePassthroughDouble(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: "`++__A *B*__++`",
		exp:     "<code>__A *B*__</code>",
	}, {
		content: "`++__A *B*__+`",
		exp:     "<code><em>A <strong>B</strong></em>+</code>",
	}, {
		content: `\++__A *B*__++`,
		exp:     `+__A *B*__+`,
	}, {
		content: `+\+__A *B*__++`,
		exp:     `+__A *B*__+`,
	}, {
		content: `++__A *B*__\++`,
		exp:     `<em>A <strong>B</strong></em>++`,
	}, {
		content: `++__A *B*__+\+`,
		exp:     `<em>A <strong>B</strong></em>++`,
	}, {
		content: `++ <u>A</u> ++`,
		exp:     ` <u>A</u> `,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parsePassthroughTriple(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `+++__A *B*__+++`,
		exp:     `__A *B*__`,
	}, {
		content: `+++__A *B*__++`,
		exp:     `+__A *B*__`,
	}, {
		content: `\+++__A *B*__+++`,
		exp:     `+__A *B*__+`,
	}, {
		content: `+\++__A *B*__+++`,
		exp:     `+<em>A <strong>B</strong></em>+`,
	}, {
		content: `++\+__A *B*__+++`,
		exp:     `+__A *B*__+`,
	}, {
		content: `+++__A *B*__\+++`,
		exp:     `+__A *B*__+`,
	}, {
		content: `+++__A *B*__+\++`,
		exp:     `__A *B*__++`,
	}, {
		content: `+++__A *B*__++\+`,
		exp:     `+__A *B*__+`,
	}, {
		content: `+++ <u>A</u> +++`,
		exp:     ` <u>A</u> `,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
			anchors: map[string]*anchor{
				`x`: &anchor{
					label: `X y`,
				},
			},
			titleID: map[string]string{
				`X y`: `x`,
			},
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseQuote(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: "\"`A double quote without end.",
		exp:     "\"`A double quote without end.",
	}, {
		content: "\"` A double quote around space `\"",
		exp:     "\"` A double quote around space `\"",
	}, {
		content: "\"`A double quote`\"",
		exp:     "&#8220;A double quote&#8221;",
	}, {
		content: "\"`Escaped double quote\\`\"",
		exp:     "\"`Escaped double quote`\"",
	}, {
		content: "'`A single quote without end.",
		exp:     "'`A single quote without end.",
	}, {
		content: "'` A single quote around space `'",
		exp:     "'` A single quote around space &#8217;",
	}, {
		content: "\"`A single quote`\"",
		exp:     "&#8220;A single quote&#8221;",
	}, {
		content: "\"`Escaped single quote\\`\"",
		exp:     "\"`Escaped single quote`\"",
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		tdata     *test.Data
		container *element
		got       string
		err       error
		name      string
		lineNum   string
		vbytes    []byte
		exps      [][]byte
		lines     [][]byte
		x         int
	)
	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	tdata, err = test.LoadData(`testdata/inline_parser/inline_parser_test.txt`)
	if err != nil {
		t.Fatal(err)
	}
}

func TestInlineParser_parseSubscsript(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}
	for name, vbytes = range tdata.Input {
		t.Run(name, func(t *testing.T) {
			lines = bytes.Split(vbytes, []byte("\n"))
			exps = bytes.Split(tdata.Output[name], []byte("\n"))

	var cases = []testCase{{
		content: "A~B~C",
		exp:     "A<sub>B</sub>C",
	}, {
		content: "A~B ~C",
		exp:     "A~B ~C",
	}, {
		content: "A~ B~C",
		exp:     "A~ B~C",
	}, {
		content: `A\~B~C`,
		exp:     "A~B~C",
	}, {
		content: `A~B\~C`,
		exp:     "A~B~C",
	}}
			for x, vbytes = range lines {
				buf.Reset()
				container = parseInlineMarkup(_testDoc, vbytes)
				container.toHTML(_testDoc, &buf)

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}
}

func TestInlineParser_parseSuperscript(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
	}

	var cases = []testCase{{
		content: `A^B^C`,
		exp:     `A<sup>B</sup>C`,
	}, {
		content: `A^B ^C`,
		exp:     `A^B ^C`,
	}, {
		content: `A^ B^C`,
		exp:     `A^ B^C`,
	}, {
		content: `A\^B^C`,
		exp:     `A^B^C`,
	}, {
		content: `A^B\^C`,
		exp:     `A^B^C`,
	}}

	var (
		buf       bytes.Buffer
		c         testCase
		container *element
		got       string
	)

	for _, c = range cases {
		buf.Reset()

		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
				lineNum = fmt.Sprintf("#%d", x)
				test.Assert(t, lineNum, string(exps[x]), buf.String())
			}
		})
	}
}

func TestInlineParser_parseURL(t *testing.T) {
func TestInlineParser_parseInlineID_isForToC(t *testing.T) {
	type testCase struct {
		content string
		exp     string
	}

	var _testDoc = &Document{
		anchors: make(map[string]*anchor),
		titleID: make(map[string]string),
		anchors:  make(map[string]*anchor),
		titleID:  make(map[string]string),
		isForToC: true,
	}

	var cases = []testCase{{
		content: `https://asciidoctor.org/abc`,
		exp:     `<a href="https://asciidoctor.org/abc" class="bare">https://asciidoctor.org/abc</a>`,
	}, {
		content: `https://asciidoctor.org.`,
		exp:     `<a href="https://asciidoctor.org" class="bare">https://asciidoctor.org</a>.`,
	}, {
		content: `https://asciidoctor.org[Asciidoctor^,role="a,b"].`,
		exp:     `<a href="https://asciidoctor.org" class="a b" target="_blank" rel="noopener">Asciidoctor</a>.`,
	}, {
		content: `\https://example.org.`,
		exp:     `https://example.org.`,
	}, {
		content: `irc://irc.freenode.org/#fedora[Fedora IRC channel].`,
		exp:     `<a href="irc://irc.freenode.org/#fedora">Fedora IRC channel</a>.`,
	}, {
		content: `mailto:ms@kilabit.info.`,
		exp:     `<a href="mailto:ms@kilabit.info">mailto:ms@kilabit.info</a>.`,
	}, {
		content: `mailto:ms@kilabit.info[Mail to me].`,
		exp:     `<a href="mailto:ms@kilabit.info">Mail to me</a>.`,
	}, {
		content: `Relative file link:test.html[test.html].`,
		exp:     `Relative file <a href="test.html">test.html</a>.`,
	}, {
		content: `link:https://kilabit.info[Kilabit^].`,
		exp:     `<a href="https://kilabit.info" target="_blank" rel="noopener">Kilabit</a>.`,
	}, {
		content: `http: this is not link`,
		exp:     `http: this is not link`,
		content: `[[A]] B`,
		exp:     ` B`,
	}}

	var (


@@ 818,10 92,6 @@ func TestInlineParser_parseURL(t *testing.T) {
		container = parseInlineMarkup(_testDoc, []byte(c.content))
		container.toHTML(_testDoc, &buf)

		if debug.Value > 0 {
			container.debug(0)
		}

		got = buf.String()
		test.Assert(t, c.content, c.exp, got)
	}

A testdata/inline_parser/inline_parser_test.txt => testdata/inline_parser/inline_parser_test.txt +247 -0
@@ 0,0 1,247 @@
Various tests for inlineParser.

>>>
*A _B `C_ D` E*
A * B *, C *=*.
*A _B `C D* E_ F.

<<<
<strong>A <em>B <code>C</code></em><code> D</code> E</strong>
A * B <strong>, C *=</strong>.
<strong>A <em>B `C D</em></strong><em> E</em> F.

>>> parseAttrRef
A {x}[*B*] C
A {x }[*B*] C
A {x }*B* C
A {y }*B* C

<<< parseAttrRef
A <a href="https://kilabit.info"><strong>B</strong></a> C
A <a href="https://kilabit.info"><strong>B</strong></a> C
A <a href="https://kilabit.info*B*" class="bare">https://kilabit.info*B*</a> C
A {y }<strong>B</strong> C

>>> parseCrossRef
A <<x>>
A <<x, Label>>
A <<X y>>
A <<X y,Label>>

<<< parseCrossRef
A <a href="#x">X y</a>
A <a href="#x">Label</a>
A <a href="#x">X y</a>
A <a href="#x">Label</a>

>>> parseFormat
_A_B
_A_ B
_A _B
*A*B
*A* B
*A *B
`A`B
`A` B
`A `B
A `/**/` *B*

<<< parseFormat
_A_B
<em>A</em> B
_A _B
*A*B
<strong>A</strong> B
*A *B
`A`B
<code>A</code> B
`A `B
A <code>/<strong></strong>/</code> <strong>B</strong>

>>> parseFormatUnconstrained
__A__B
__A *B*__
__A _B_ C__
__A B_ C__
__A *B*_
_A *B*__

<<< parseFormatUnconstrained
<em>A</em>B
<em>A <strong>B</strong></em>
<em>A <em>B</em> C</em>
<em>A B_ C</em>
<em>_A <strong>B</strong></em>
<em>A <strong>B</strong>_</em>

>>> parseInlineID
[[A]] B
[[A] B
[A]] B
[[A ]] B
[[ A]] B
[[A B]] C

<<< parseInlineID
<a id="A"></a> B
[[A] B
[A]] B
[[A ]] B
[[ A]] B
[[A B]] C

>>> parseInlineIDShort
[#Q]#W#
[#Q]#W
[#Q]W#
[#Q ]#W#
[# Q]# W#
[#Q W]# E#

<<< parseInlineIDShort
<span id="Q">W</span>
[#Q]#W
[#Q]W#
[#Q ]#W#
[# Q]# W#
[#Q W]# E#

>>> parseInlineImage
image:https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg[Linux,25,35]
image:linux.png[Linux,150,150,float="right"] You can find Linux everywhere these days!
image:sunset.jpg[Sunset,150,150,role="right"] What a beautiful sunset!
image:sunset.jpg[Sunset]
image:linux.png[2]

<<< parseInlineImage
<span class="image"><img src="https://upload.wikimedia.org/wikipedia/commons/3/35/Tux.svg" alt="Linux" width="25" height="35"></span>
<span class="image right"><img src="linux.png" alt="Linux" width="150" height="150"></span> You can find Linux everywhere these days!
<span class="image right"><img src="sunset.jpg" alt="Sunset" width="150" height="150"></span> What a beautiful sunset!
<span class="image"><img src="sunset.jpg" alt="Sunset"></span>
<span class="image"><img src="linux.png" alt="2"></span>

>>> parsePassthrough
`+__A *B*__+`
\+__A *B*__+
+__A *B*__\+
X+__A *B*__+
+__A *B*__+X

<<< parsePassthrough
<code>__A *B*__</code>
+<em>A <strong>B</strong></em>+
+<em>A <strong>B</strong></em>+
X+<em>A <strong>B</strong></em>+
+<em>A <strong>B</strong></em>+X

>>> parsePassthroughDouble
`++__A *B*__++`
`++__A *B*__+`
\++__A *B*__++
+\+__A *B*__++
++__A *B*__\++
++__A *B*__+\+
++ <u>A</u> ++.

<<< parsePassthroughDouble
<code>__A *B*__</code>
<code><em>A <strong>B</strong></em>+</code>
+__A *B*__+
+__A *B*__+
<em>A <strong>B</strong></em>++
<em>A <strong>B</strong></em>++
 <u>A</u> .

>>> parsePassthroughTriple
+++__A *B*__+++
+++__A *B*__++
\+++__A *B*__+++
+\++__A *B*__+++
++\+__A *B*__+++
+++__A *B*__\+++
+++__A *B*__+\++
+++__A *B*__++\+
+++ <u>A</u> +++.

<<< parsePassthroughTriple
__A *B*__
+__A *B*__
+__A *B*__+
+<em>A <strong>B</strong></em>+
+__A *B*__+
+__A *B*__+
__A *B*__++
+__A *B*__+
 <u>A</u> .

>>> parseQuote
"`A double quote without end.
"` A double quote around space `"
"`A double quote`"
"`Escaped double quote\`"
'`A single quote without end.
'` A single quote around space `'
"`A single quote`"
"`Escaped single quote\`"

<<< parseQuote
"`A double quote without end.
"` A double quote around space `"
&#8220;A double quote&#8221;
"`Escaped double quote`"
'`A single quote without end.
'` A single quote around space &#8217;
&#8220;A single quote&#8221;
"`Escaped single quote`"

>>> parseSubscript
A~B~C
A~B ~C
A~ B~C
A\~B~C
A~B\~C

<<< parseSubscript
A<sub>B</sub>C
A~B ~C
A~ B~C
A~B~C
A~B~C

>>> parseSuperscript
A^B^C
A^B ^C
A^ B^C
A\^B^C
A^B\^C

<<< parseSuperscript
A<sup>B</sup>C
A^B ^C
A^ B^C
A^B^C
A^B^C

>>> parseURL
https://asciidoctor.org/abc
https://asciidoctor.org.
https://asciidoctor.org[Asciidoctor^,role="a,b"].
\https://example.org.
irc://irc.freenode.org/#fedora[Fedora IRC channel].
mailto:ms@kilabit.info.
mailto:ms@kilabit.info[Mail to me].
Relative file link:test.html[test.html].
link:https://kilabit.info[Kilabit^].
http: this is not link

<<< parseURL
<a href="https://asciidoctor.org/abc" class="bare">https://asciidoctor.org/abc</a>
<a href="https://asciidoctor.org" class="bare">https://asciidoctor.org</a>.
<a href="https://asciidoctor.org" class="a b" target="_blank" rel="noopener">Asciidoctor</a>.
https://example.org.
<a href="irc://irc.freenode.org/#fedora">Fedora IRC channel</a>.
<a href="mailto:ms@kilabit.info">mailto:ms@kilabit.info</a>.
<a href="mailto:ms@kilabit.info">Mail to me</a>.
Relative file <a href="test.html">test.html</a>.
<a href="https://kilabit.info" target="_blank" rel="noopener">Kilabit</a>.
http: this is not link