package format
import (
"strings"
"testing"
"unicode/utf8"
"github.com/stretchr/testify/assert"
)
func TestPrettyXML_Paragraph(t *testing.T) {
input := `<p>Hello <strong>world</strong></p>`
result := PrettyXML(input, " ")
assert.Equal(t, "<p>\n Hello <strong>world</strong>\n</p>\n", result)
}
func TestPrettyXML_NestedBlocks(t *testing.T) {
input := `<ul><li>One</li><li>Two</li></ul>`
result := PrettyXML(input, " ")
// li should be inlined since content is short
assert.Contains(t, result, " <li>One</li>\n")
assert.Contains(t, result, " <li>Two</li>\n")
}
func TestPrettyXML_InlineStaysInline(t *testing.T) {
input := `<p>Text with <strong>bold</strong> and <em>italic</em></p>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "Text with <strong>bold</strong> and <em>italic</em>")
}
func TestPrettyXML_CodeBlockCDATAPreserved(t *testing.T) {
input := `<ac:structured-macro ac:name="code"><ac:parameter ac:name="language">go</ac:parameter><ac:plain-text-body><![CDATA[func main() {
fmt.Println("hello")
}]]></ac:plain-text-body></ac:structured-macro>`
result := PrettyXML(input, " ")
assert.Contains(t, result, `<![CDATA[func main() {
fmt.Println("hello")
}]]>`)
}
func TestPrettyXML_HeadingsInlined(t *testing.T) {
input := `<h1>Title</h1><h2>Subtitle</h2>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<h1>Title</h1>\n")
assert.Contains(t, result, "<h2>Subtitle</h2>\n")
}
func TestPrettyXML_HeadingsWithInlineMarkup(t *testing.T) {
input := `<h2>Section <strong>Important</strong></h2>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<h2>Section <strong>Important</strong></h2>\n")
}
func TestPrettyXML_SelfClosingBlock(t *testing.T) {
input := `<p>Before</p><hr/><p>After</p>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<hr/>\n")
}
func TestPrettyXML_Table(t *testing.T) {
input := `<table><tbody><tr><th><p>Name</p></th><td><p>Value</p></td></tr></tbody></table>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<table>\n")
assert.Contains(t, result, " <tbody>\n")
assert.Contains(t, result, " <tr>\n")
}
func TestPrettyXML_Layout(t *testing.T) {
input := `<ac:layout><ac:layout-section ac:type="single"><ac:layout-cell><p>Content</p></ac:layout-cell></ac:layout-section></ac:layout>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<ac:layout>\n")
assert.Contains(t, result, " <ac:layout-section ac:type=\"single\">\n")
assert.Contains(t, result, " <ac:layout-cell>\n")
}
func TestPrettyXML_TaskList(t *testing.T) {
input := `<ac:task-list><ac:task><ac:task-id>1</ac:task-id><ac:task-status>complete</ac:task-status><ac:task-body>Done</ac:task-body></ac:task></ac:task-list>`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<ac:task-list>\n")
assert.Contains(t, result, " <ac:task>\n")
// task-id and task-status should be inlined
assert.Contains(t, result, "<ac:task-id>1</ac:task-id>")
assert.Contains(t, result, "<ac:task-status>complete</ac:task-status>")
}
func TestPrettyXML_CommentsPreserved(t *testing.T) {
input := `<!-- MD_CONTENT_START --><p>Content</p><!-- MD_CONTENT_END -->`
result := PrettyXML(input, " ")
assert.Contains(t, result, "<!-- MD_CONTENT_START -->")
assert.Contains(t, result, "<!-- MD_CONTENT_END -->")
}
func TestPrettyXML_InlineElements(t *testing.T) {
input := `<p>Link: <a href="https://example.com">click</a> and <code>code</code></p>`
result := PrettyXML(input, " ")
assert.Contains(t, result, `Link: <a href="https://example.com">click</a> and <code>code</code>`)
}
func TestPrettyXML_EmptyInput(t *testing.T) {
result := PrettyXML("", " ")
assert.Equal(t, "\n", result)
}
func TestPrettyXML_UserAndAttachmentInline(t *testing.T) {
input := `<p>By <ac:link><ri:user ri:userkey="abc123"/></ac:link> see <ac:image><ri:attachment ri:filename="img.png"/></ac:image></p>`
result := PrettyXML(input, " ")
assert.Contains(t, result, `<ac:link><ri:user ri:userkey="abc123"/></ac:link>`)
}
func TestPrettyXML_CustomIndent(t *testing.T) {
input := `<ul><li>Item</li></ul>`
result := PrettyXML(input, "\t")
assert.Contains(t, result, "\t<li>Item</li>")
}
func TestPrettyXML_LiInlinedShort(t *testing.T) {
input := `<ul><li>Short item</li></ul>`
result := PrettyXML(input, " ")
assert.Contains(t, result, " <li>Short item</li>\n")
}
func TestPrettyXML_LiExpandedLong(t *testing.T) {
longText := strings.Repeat("слово ", 30) // ~180 chars in Cyrillic
input := `<ul><li>` + longText + `</li></ul>`
result := PrettyXML(input, " ")
// Should NOT be inlined — too long
assert.Contains(t, result, " <li>\n")
}
func TestPrettyXML_LongLineWrapped(t *testing.T) {
longText := strings.Repeat("word ", 30) // 150 chars
input := `<p>` + longText + `</p>`
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 := `<p>` + longText + `</p>`
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 := `<p>Text <strong>bold text here</strong> more text and <a href="https://example.com/very/long/path">some link</a> even more text to make line long enough to wrap around the boundary limit</p>`
result := PrettyXML(input, " ")
// Tags should not be split across lines
assert.NotContains(t, result, "<strong\n")
assert.NotContains(t, result, "</strong\n")
}