package format
import (
"strings"
"testing"
"unicode/utf8"
"github.com/stretchr/testify/assert"
)
func TestPrettyXML_Paragraph(t *testing.T) {
input := `
Hello world
`
result := PrettyXML(input, " ")
assert.Equal(t, "\n Hello world\n
\n", result)
}
func TestPrettyXML_NestedBlocks(t *testing.T) {
input := ``
result := PrettyXML(input, " ")
// li should be inlined since content is short
assert.Contains(t, result, " One\n")
assert.Contains(t, result, " Two\n")
}
func TestPrettyXML_InlineStaysInline(t *testing.T) {
input := `Text with bold and italic
`
result := PrettyXML(input, " ")
assert.Contains(t, result, "Text with bold and italic")
}
func TestPrettyXML_CodeBlockCDATAPreserved(t *testing.T) {
input := `go`
result := PrettyXML(input, " ")
assert.Contains(t, result, ``)
}
func TestPrettyXML_HeadingsInlined(t *testing.T) {
input := `Title
Subtitle
`
result := PrettyXML(input, " ")
assert.Contains(t, result, "Title
\n")
assert.Contains(t, result, "Subtitle
\n")
}
func TestPrettyXML_HeadingsWithInlineMarkup(t *testing.T) {
input := `Section Important
`
result := PrettyXML(input, " ")
assert.Contains(t, result, "Section Important
\n")
}
func TestPrettyXML_SelfClosingBlock(t *testing.T) {
input := `Before
After
`
result := PrettyXML(input, " ")
// Formatter normalizes self-closing tags to "" form.
assert.Contains(t, result, "
\n")
}
func TestPrettyXML_Table(t *testing.T) {
input := ``
result := PrettyXML(input, " ")
assert.Contains(t, result, "\n")
assert.Contains(t, result, " \n")
assert.Contains(t, result, " \n")
}
func TestPrettyXML_Layout(t *testing.T) {
input := `Content
`
result := PrettyXML(input, " ")
assert.Contains(t, result, "\n")
assert.Contains(t, result, " \n")
assert.Contains(t, result, " \n")
}
func TestPrettyXML_TaskList(t *testing.T) {
input := `1completeDone`
result := PrettyXML(input, " ")
assert.Contains(t, result, "\n")
assert.Contains(t, result, " \n")
// task-id and task-status should be inlined
assert.Contains(t, result, "1")
assert.Contains(t, result, "complete")
}
func TestPrettyXML_CommentsPreserved(t *testing.T) {
input := `Content
`
result := PrettyXML(input, " ")
assert.Contains(t, result, "")
assert.Contains(t, result, "")
}
func TestPrettyXML_InlineElements(t *testing.T) {
input := `Link: click and code
`
result := PrettyXML(input, " ")
assert.Contains(t, result, `Link: click and code`)
}
func TestPrettyXML_EmptyInput(t *testing.T) {
result := PrettyXML("", " ")
assert.Equal(t, "\n", result)
}
func TestPrettyXML_UserAndAttachmentInline(t *testing.T) {
input := `By see
`
result := PrettyXML(input, " ")
// Formatter normalizes self-closing tags to "" form.
assert.Contains(t, result, ``)
}
func TestPrettyXML_CustomIndent(t *testing.T) {
input := ``
result := PrettyXML(input, "\t")
assert.Contains(t, result, "\tItem")
}
func TestPrettyXML_LiInlinedShort(t *testing.T) {
input := ``
result := PrettyXML(input, " ")
assert.Contains(t, result, " Short item\n")
}
func TestPrettyXML_LiExpandedLong(t *testing.T) {
longText := strings.Repeat("слово ", 30) // ~180 chars in Cyrillic
input := ``
result := PrettyXML(input, " ")
// Should NOT be inlined — too long
assert.Contains(t, result, " \n")
}
func TestPrettyXML_LongLineWrapped(t *testing.T) {
longText := strings.Repeat("word ", 30) // 150 chars
input := `` + longText + `
`
result := PrettyXML(input, " ")
for _, line := range strings.Split(result, "\n") {
w := utf8.RuneCountInString(line)
if w > 125 { // allow small overshoot for tags
t.Errorf("line too long (%d runes): %s", w, line)
}
}
}
func TestPrettyXML_LongLineUTF8(t *testing.T) {
// Russian text: each Cyrillic char is 1 rune but 2 bytes
longText := strings.Repeat("Привет мир ", 15) // ~165 runes
input := `` + longText + `
`
result := PrettyXML(input, " ")
for _, line := range strings.Split(result, "\n") {
w := utf8.RuneCountInString(line)
if w > 125 {
t.Errorf("line too long (%d runes): %s", w, line[:80])
}
}
}
func TestPrettyXML_LongLinePreservesTagIntegrity(t *testing.T) {
input := `Text bold text here more text and some link even more text to make line long enough to wrap around the boundary limit
`
result := PrettyXML(input, " ")
// Tags should not be split across lines
assert.NotContains(t, result, ""). Regression for the
// "missing space before inline code" report.
func TestPrettyXML_SpaceBetweenInlineElements(t *testing.T) {
cases := []struct{ input, want string }{
{`Bold word code here.
`, " "},
{`Link t code here.
`, " "},
{`Word em code.
`, " "},
}
for _, tc := range cases {
result := PrettyXML(tc.input, " ")
assert.Contains(t, result, tc.want, tc.input)
}
}
// The same significant space must also survive when the line is long enough to
// be wrapped: wrapLine used to drop whitespace that sat between a word/tag and
// an adjacent tag, because strings.Fields discarded trailing space and tags
// ignored any pending space.
func TestPrettyXML_WrapPreservesSpaceBeforeTag(t *testing.T) {
long := strings.Repeat("слово ", 25) // push past the 120-rune wrap width
input := `` + long + `жирный код хвост предложения.
`
result := PrettyXML(input, " ")
assert.NotContains(t, result, "")
assert.Contains(t, result, " ")
}
// The literal reported pattern: a plain word followed by inline code on a line
// long enough to wrap. wrapLine's strings.Fields dropped the word's trailing
// space, gluing it to ("манифеста" instead of "манифеста ").
func TestPrettyXML_WrapPreservesSpaceBeforeCodeAfterWord(t *testing.T) {
long := strings.Repeat("текст ", 25) // push past the 120-rune wrap width
input := `` + long + `манифеста app.manifest.toml и далее.
`
result := PrettyXML(input, " ")
assert.NotContains(t, result, "манифеста")
assert.Contains(t, result, "манифеста ")
}
// A wrap must never fall inside ...: doing so injects the
// continuation indent into the code text, which round-trips as a spurious space
// inside the span. The whole span is kept on one line regardless of where the
// boundary lands. Probes several lengths so the wrap point sweeps across the
// code span's open tag.
func TestPrettyXML_WrapKeepsCodeSpanWhole(t *testing.T) {
for n := 18; n <= 24; n++ {
input := `` + strings.Repeat("word ", n) + `tail app.manifest.lock rest of it.
`
result := PrettyXML(input, " ")
for _, line := range strings.Split(result, "\n") {
trimmed := strings.TrimSpace(line)
// No line may start or end mid-span (open without close, or vice versa).
assert.False(t, strings.HasPrefix(trimmed, "app.manifest.lock"),
"code content split onto its own line at n=%d: %q", n, line)
if strings.Contains(line, "") {
assert.Contains(t, line, "",
" opened but not closed on same line at n=%d: %q", n, line)
}
}
}
}