summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2022-08-06 01:16:08 +0700
committerShulhan <ms@kilabit.info>2022-08-06 01:17:10 +0700
commit9fe1ecf6050bbebfe4096e5c41a1e711dd16190d (patch)
tree29e4593dffc64d5d34950a07b79d2339fb596910
parent502ccd5e3f41f4fd1b3bfa1fad2c41785db1a7d1 (diff)
downloadasciidoctor-go-9fe1ecf6050bbebfe4096e5c41a1e711dd16190d.tar.xz
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.
-rw-r--r--element.go14
-rw-r--r--inline_parser.go6
-rw-r--r--inline_parser_test.go814
-rw-r--r--testdata/inline_parser/inline_parser_test.txt247
4 files changed, 294 insertions, 787 deletions
diff --git a/element.go b/element.go
index 46d045d..a558055 100644
--- a/element.go
+++ b/element.go
@@ -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
diff --git a/inline_parser.go b/inline_parser.go
index 62287bf..881374e 100644
--- a/inline_parser.go
+++ b/inline_parser.go
@@ -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]
}
diff --git a/inline_parser_test.go b/inline_parser_test.go
index c26b209..62c4f74 100644
--- a/inline_parser_test.go
+++ b/inline_parser_test.go
@@ -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)
}
diff --git a/testdata/inline_parser/inline_parser_test.txt b/testdata/inline_parser/inline_parser_test.txt
new file mode 100644
index 0000000..b40465d
--- /dev/null
+++ b/testdata/inline_parser/inline_parser_test.txt
@@ -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