package web
import (
"encoding/json"
"strings"
"testing"
)
// #381: a stack whose middle rung conflicts lands the rungs below it,
// and the strip says so instead of "nothing in this stack lands".
func TestAStoppedStackSaysWhatLandingLands(t *testing.T) {
render := func(landCount int) string {
var stack stackView
if err := json.Unmarshal([]byte(`{"segments":[
{"id":"r1aaaaaaaaaa","number":1,"position":1,"state":"open"},
{"id":"r2aaaaaaaaaa","number":2,"position":2,"state":"open","preflight":"conflict","preflightConflicts":["s2.txt"]},
{"id":"r3aaaaaaaaaa","number":3,"position":3,"state":"open"}],
"preflight":"stops","stopsAt":2,"landTo":"r1aaaaaaaaaa","landCount":`+itoa(landCount)+`}`), &stack); err != nil {
t.Fatal(err)
}
var buf strings.Builder
if err := noHooks.template(landingPage).ExecuteTemplate(&buf, "landing-body", pageData{Repo: "quarry",
Landing: &landingDetail{landingRow: landingRow{ID: "r3aaaaaaaaaa", Branch: "s3", Target: "s2", State: "open"},
Position: 3, Stack: stack}}); err != nil {
t.Fatal(err)
}
return buf.String()
}
got := render(1)
if !strings.Contains(got, `data-hook="stack-stops-lands" data-count="1"`) || strings.Contains(got, "Nothing in this stack lands") {
t.Error("FAIL: a stack that lands its bottom rung says nothing in it lands")
}
if got := render(0); !strings.Contains(got, `data-hook="stack-stops-lands" data-count="0"`) {
t.Error("FAIL: a stack stopped at its base does not say nothing lands")
}
}
// #382: a comment shown as text decodes its character references, as
// the body does, and the page escapes it once.
func TestCommentTextDecodesCharacterReferences(t *testing.T) {
if got := commentText("0.0<B<1.0 and AT&T — [/wiki?name=X | a & b]"); got != "0.0<B<1.0 and AT&T — a & b" {
t.Errorf("FAIL: commentText = %q", got)
}
}
// #382's leftover: a landing title whose "<b>" was written as
// "<b>" keeps it as text; firstLine's tag stripping dropped it.
func TestALandingTitleKeepsTagShapedText(t *testing.T) {
if got := titleLine("entities & <b> — done\nmore"); got != "entities & <b> — done" {
t.Errorf("FAIL: titleLine = %q", got)
}
var buf strings.Builder
if err := noHooks.template(landingPage).ExecuteTemplate(&buf, "landing-body", pageData{Repo: "quarry", OwnH1: true,
Landing: &landingDetail{landingRow: landingRow{ID: "aa11bb22cc33", Branch: "b", Target: "trunk", State: "open",
Title: "entities & <b> — done"}}}); err != nil {
t.Fatal(err)
}
if got := buf.String(); !strings.Contains(got, "entities & <b> — done") {
t.Error("FAIL: the landing h1 lost the title's tag-shaped text")
}
}
// jva: the base rung of a stack offered "Accept and land" and "Land
// stack (3)" as two primary buttons with different scope. When the
// stack lands more than this rung, the whole stack is the one primary
// action and this rung alone is the quiet alternative.
func TestTheBaseRungHasOnePrimaryAction(t *testing.T) {
render := func(landCount int) string {
var stack stackView
if err := json.Unmarshal([]byte(`{"segments":[
{"id":"r1aaaaaaaaaa","number":1,"position":1,"state":"open"},
{"id":"r2aaaaaaaaaa","number":2,"position":2,"state":"open"},
{"id":"r3aaaaaaaaaa","number":3,"position":3,"state":"open"}],
"landTo":"r3aaaaaaaaaa","landCount":`+itoa(landCount)+`}`), &stack); err != nil {
t.Fatal(err)
}
var buf strings.Builder
if err := noHooks.template(landingPage).ExecuteTemplate(&buf, "landing-decide", pageData{Repo: "quarry",
Landing: &landingDetail{landingRow: landingRow{ID: "r1aaaaaaaaaa", Branch: "s1", Target: "trunk", State: "open"},
CanAccept: true, Position: 1, Stack: stack}}); err != nil {
t.Fatal(err)
}
return buf.String()
}
got := render(3)
stack, only := strings.Index(got, `data-hook="land-stack"`), strings.Index(got, `data-hook="land-this-only"`)
if stack < 0 || only < 0 || stack > only {
t.Fatalf("FAIL: the base rung lacks land-stack then land-this-only: %s", got)
}
tag := got[strings.LastIndex(got[:only], "<button"):]
tag = tag[:strings.Index(tag, ">")]
if strings.Count(got, `class="btn-primary"`) != 1 || !strings.Contains(tag, "btn-quiet") {
t.Errorf("FAIL: want exactly one primary (the stack) and a quiet single-rung control: %s", got)
}
// A stack that can land only this rung keeps the plain accept.
if got := render(1); !strings.Contains(got, "Accept and land") || strings.Contains(got, `data-hook="land-this-only"`) {
t.Errorf("FAIL: a one-rung land lost its plain accept")
}
}