diff --git a/internal/markup/markup_test.go b/internal/markup/markup_test.go index 364c201..74848e2 100644 --- a/internal/markup/markup_test.go +++ b/internal/markup/markup_test.go @@ -176,3 +176,78 @@ func TestABrokenPageIsReportedOnceRatherThanGuessedAt(t *testing.T) { t.Errorf("the one problem reported is %s rather than the structure it stopped at", got[0].Kind) } } + +// A page that stops in the middle of a tag. Every case here is a raw fragment +// rather than a wrapped one, and deliberately: what is being read is what the +// tag reader does when the bytes run out under it, and wrapping would put a +// closing body after the point each case is about. +// +// A template that stops writing produces exactly these. What they must not do +// is index past the end of what was written: the walk reads the byte after the +// one it tested at nine places, and each place is a byte the page does not +// have. +func TestAPageThatEndsInTheMiddleOfATagIsRefusedRatherThanReadPastItsEnd(t *testing.T) { + for name, fragment := range map[string]string{ + "a tag name that runs to the end": "`, + "spaces around the equals sign": `
`, + "an attribute carrying no value": ` `, + "a void element closed with a slash": `
`, + "a raw text element with nothing inside": ` `, + "a comment holding what looks like a tag": `

A paragraph.

`, + "a comment ending on a stray bracket": `

A paragraph.

`, + } { + if got := Read(page(body)); len(got) != 0 { + t.Errorf("%s: %q was refused: %v", name, body, got) + } + } +} + +// The heading rule refuses a level that was skipped and nothing else. The three +// cases it must leave alone are the first heading on a page, whatever level it +// is, the level directly under the last one, and the deepest level reached that +// way; the fourth is the jump it exists for, and it is here so that the pair is +// one case rather than two files apart. +func TestOnlyASkippedHeadingLevelIsRefused(t *testing.T) { + for name, body := range map[string]string{ + "a first heading that is not the top level": `

A section

`, + "the level directly under the last one": `

A title

A section

`, + "the deepest level under the one above it": `

A

B
C
`, + } { + if got := Of(Heading, Read(page(body))); len(got) != 0 { + t.Errorf("%s: %q was refused: %v", name, body, got) + } + } + if got := Of(Heading, Read(page(`

A title

Six
`))); len(got) != 1 { + t.Errorf("a jump from the top level to the deepest was read as %d problem(s): %v", len(got), got) + } +}