From ae8027637c91c400af8a3e006c35c7011b3ca1fe Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Sun, 29 Apr 2018 00:50:38 +0530 Subject: [PATCH] godoc/static: add test for static.go file generation Moved the code which generates static.go to remain in the static package. This makes the code testable. Additionally, it is very easy for developers to forget to run "go generate" to update static.go. Because while development, the templates directory can be directly passed as a flag to read the files from it. This test catches that. Change-Id: I314907b98907bb14e4eabfd3c532ba2d84ce7c5f Reviewed-on: https://go-review.googlesource.com/110158 Reviewed-by: Brad Fitzpatrick Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot --- godoc/static/gen.go | 103 +++++++++++++++++++++++++++++++++++ godoc/static/gen_test.go | 27 ++++++++++ godoc/static/makestatic.go | 107 ++++--------------------------------- 3 files changed, 140 insertions(+), 97 deletions(-) create mode 100644 godoc/static/gen_test.go diff --git a/godoc/static/gen.go b/godoc/static/gen.go index 42268211e4..5ffa6d0c52 100644 --- a/godoc/static/gen.go +++ b/godoc/static/gen.go @@ -5,3 +5,106 @@ package static //go:generate go run makestatic.go + +import ( + "bytes" + "fmt" + "go/format" + "io/ioutil" + "time" + "unicode/utf8" +) + +var files = []string{ + "analysis/call3.png", + "analysis/call-eg.png", + "analysis/callers1.png", + "analysis/callers2.png", + "analysis/chan1.png", + "analysis/chan2a.png", + "analysis/chan2b.png", + "analysis/error1.png", + "analysis/help.html", + "analysis/ident-def.png", + "analysis/ident-field.png", + "analysis/ident-func.png", + "analysis/ipcg-func.png", + "analysis/ipcg-pkg.png", + "analysis/typeinfo-pkg.png", + "analysis/typeinfo-src.png", + "callgraph.html", + "codewalk.html", + "codewalkdir.html", + "dirlist.html", + "error.html", + "example.html", + "godoc.html", + "godocs.js", + "images/minus.gif", + "images/plus.gif", + "images/treeview-black-line.gif", + "images/treeview-black.gif", + "images/treeview-default-line.gif", + "images/treeview-default.gif", + "images/treeview-gray-line.gif", + "images/treeview-gray.gif", + "implements.html", + "jquery.js", + "jquery.treeview.css", + "jquery.treeview.edit.js", + "jquery.treeview.js", + "methodset.html", + "opensearch.xml", + "package.html", + "packageroot.html", + "package.txt", + "play.js", + "playground.js", + "search.html", + "search.txt", + "searchcode.html", + "searchdoc.html", + "searchtxt.html", + "style.css", +} + +// Generate reads a set of files and returns a file buffer that declares +// a map of string constants containing contents of the input files. +func Generate() ([]byte, error) { + buf := new(bytes.Buffer) + fmt.Fprintf(buf, "%v\n\n%v\n\npackage static\n\n", license, warning) + fmt.Fprintf(buf, "var Files = map[string]string{\n") + for _, fn := range files { + b, err := ioutil.ReadFile(fn) + if err != nil { + return b, err + } + fmt.Fprintf(buf, "\t%q: ", fn) + if utf8.Valid(b) { + fmt.Fprintf(buf, "`%s`", sanitize(b)) + } else { + fmt.Fprintf(buf, "%q", b) + } + fmt.Fprintf(buf, ",\n\n") + } + fmt.Fprintln(buf, "}") + return format.Source(buf.Bytes()) +} + +// sanitize prepares a valid UTF-8 string as a raw string constant. +func sanitize(b []byte) []byte { + // Replace ` with `+"`"+` + b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1) + + // Replace BOM with `+"\xEF\xBB\xBF"+` + // (A BOM is valid UTF-8 but not permitted in Go source files. + // I wouldn't bother handling this, but for some insane reason + // jquery.js has a BOM somewhere in the middle.) + return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1) +} + +const warning = `// Code generated by "makestatic"; DO NOT EDIT.` + +var license = fmt.Sprintf(`// Copyright %d The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file.`, time.Now().UTC().Year()) diff --git a/godoc/static/gen_test.go b/godoc/static/gen_test.go new file mode 100644 index 0000000000..a37de8ec59 --- /dev/null +++ b/godoc/static/gen_test.go @@ -0,0 +1,27 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package static + +import ( + "bytes" + "io/ioutil" + "testing" +) + +func TestStaticIsUpToDate(t *testing.T) { + oldBuf, err := ioutil.ReadFile("static.go") + if err != nil { + t.Errorf("error while reading static.go: %v\n", err) + } + + newBuf, err := Generate() + if err != nil { + t.Errorf("error while generating static.go: %v\n", err) + } + + if bytes.Compare(oldBuf, newBuf) != 0 { + t.Error("static.go is stale") + } +} diff --git a/godoc/static/makestatic.go b/godoc/static/makestatic.go index 98ade22200..0f910f0c45 100644 --- a/godoc/static/makestatic.go +++ b/godoc/static/makestatic.go @@ -4,73 +4,17 @@ // +build ignore -// Command makestatic reads a set of files and writes a Go source file to "static.go" -// that declares a map of string constants containing contents of the input files. +// Command makestatic writes the generated file buffer to "static.go". // It is intended to be invoked via "go generate" (directive in "gen.go"). package main import ( - "bytes" "fmt" - "go/format" "io/ioutil" "os" - "time" - "unicode/utf8" -) -var files = []string{ - "analysis/call3.png", - "analysis/call-eg.png", - "analysis/callers1.png", - "analysis/callers2.png", - "analysis/chan1.png", - "analysis/chan2a.png", - "analysis/chan2b.png", - "analysis/error1.png", - "analysis/help.html", - "analysis/ident-def.png", - "analysis/ident-field.png", - "analysis/ident-func.png", - "analysis/ipcg-func.png", - "analysis/ipcg-pkg.png", - "analysis/typeinfo-pkg.png", - "analysis/typeinfo-src.png", - "callgraph.html", - "codewalk.html", - "codewalkdir.html", - "dirlist.html", - "error.html", - "example.html", - "godoc.html", - "godocs.js", - "images/minus.gif", - "images/plus.gif", - "images/treeview-black-line.gif", - "images/treeview-black.gif", - "images/treeview-default-line.gif", - "images/treeview-default.gif", - "images/treeview-gray-line.gif", - "images/treeview-gray.gif", - "implements.html", - "jquery.js", - "jquery.treeview.css", - "jquery.treeview.edit.js", - "jquery.treeview.js", - "methodset.html", - "opensearch.xml", - "package.html", - "packageroot.html", - "package.txt", - "play.js", - "playground.js", - "search.html", - "search.txt", - "searchcode.html", - "searchdoc.html", - "searchtxt.html", - "style.css", -} + "golang.org/x/tools/godoc/static" +) func main() { if err := makestatic(); err != nil { @@ -80,44 +24,13 @@ func main() { } func makestatic() error { - buf := new(bytes.Buffer) - fmt.Fprintf(buf, "%v\n\n%v\n\npackage static\n\n", license, warning) - fmt.Fprintf(buf, "var Files = map[string]string{\n") - for _, fn := range files { - b, err := ioutil.ReadFile(fn) - if err != nil { - return err - } - fmt.Fprintf(buf, "\t%q: ", fn) - if utf8.Valid(b) { - fmt.Fprintf(buf, "`%s`", sanitize(b)) - } else { - fmt.Fprintf(buf, "%q", b) - } - fmt.Fprintln(buf, ",\n") - } - fmt.Fprintln(buf, "}") - fmtbuf, err := format.Source(buf.Bytes()) + buf, err := static.Generate() if err != nil { - return err + return fmt.Errorf("error while generating static.go: %v\n", err) } - return ioutil.WriteFile("static.go", fmtbuf, 0666) + err = ioutil.WriteFile("static.go", buf, 0666) + if err != nil { + return fmt.Errorf("error while writing static.go: %v\n", err) + } + return nil } - -// sanitize prepares a valid UTF-8 string as a raw string constant. -func sanitize(b []byte) []byte { - // Replace ` with `+"`"+` - b = bytes.Replace(b, []byte("`"), []byte("`+\"`\"+`"), -1) - - // Replace BOM with `+"\xEF\xBB\xBF"+` - // (A BOM is valid UTF-8 but not permitted in Go source files. - // I wouldn't bother handling this, but for some insane reason - // jquery.js has a BOM somewhere in the middle.) - return bytes.Replace(b, []byte("\xEF\xBB\xBF"), []byte("`+\"\\xEF\\xBB\\xBF\"+`"), -1) -} - -const warning = `// Code generated by "makestatic"; DO NOT EDIT.` - -var license = fmt.Sprintf(`// Copyright %d The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file.`, time.Now().UTC().Year())