package e2e import ( "net/http" "os/exec" "strings" "testing" ) // Chapter 24 gives the file view a history link and the config page history, blame and raw. func TestOneFileHasItsOwnHistory(t *testing.T) { if _, err := exec.LookPath("git"); err != nil { t.Skip("git is not installed") } in := newInstance(t) john := in.account("john") work := seed(t, in, john, "john", "johnbot") write(t, work, "conn.go", "package irc\n\nfunc dial() error { return nil }\n") run(t, work, "git", "add", "-A") run(t, work, "git", "commit", "-qm", "add the dialer") write(t, work, "other.go", "package irc\n\nfunc unrelated() {}\n") run(t, work, "git", "add", "-A") run(t, work, "git", "commit", "-qm", "a commit that never touches the dialer") write(t, work, "conn.go", "package irc\n\nfunc dial() error { return errBusy }\n") run(t, work, "git", "add", "-A") run(t, work, "git", "commit", "-qm", "the dialer returns busy now") run(t, work, "git", "push", "-q", in.url(john, "/john/johnbot"), "master") // The file view's history link is the only way to ask this question from a page. code, _, file := get(t, in.http.URL+"/john/johnbot/file/master/conn.go") if code != http.StatusOK { t.Fatalf("the file view answered %d", code) } if !strings.Contains(file, `href="/john/johnbot?path=conn.go"`) { t.Errorf("the file view does not link to its own history:\n%s", footOf(file)) } code, _, hist := get(t, in.http.URL+"/john/johnbot?path=conn.go") if code != http.StatusOK { t.Fatalf("the history answered %d", code) } for _, want := range []string{"add the dialer", "the dialer returns busy now"} { if !strings.Contains(hist, want) { t.Errorf("the history of conn.go lost %q", want) } } // A commit that never touched the file is the whole point of asking for one file. if strings.Contains(hist, "a commit that never touches the dialer") { t.Error("the history of conn.go carries a commit that does not touch conn.go") } // Every row counts only this file, since that is what asking for one file means. if !strings.Contains(hist, "conn.go ยท +1 -1") { t.Errorf("a row does not count conn.go alone:\n%s", hist) } // And it says what it is restricted to, or a reader cannot tell it from the whole log. if !strings.Contains(hist, "history of") || !strings.Contains(hist, "the whole log") { t.Error("the history page does not say it is one file, nor offer the way back") } // The config page is a file view with a fixed path, so chapter 24 gives it all three links. code, _, cfg := get(t, in.http.URL+"/john/johnbot/config") if code != http.StatusOK { t.Fatalf("the config page answered %d", code) } for _, want := range []string{">history", ">blame", ">raw"} { if !strings.Contains(cfg, want) { t.Errorf("the config page is missing its %s link", strings.Trim(want, ">/a<")) } } } // footOf is the last of a page, which is where every one of these links lives. func footOf(body string) string { if i := strings.LastIndex(body, `class="foot"`); i >= 0 { return body[i:] } return body }