cmd/go: two testing fixes

1. Show passing output for "go test" (no args) and with -v flag.
2. Warn about out-of-date packages being rebuilt.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/5504080
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 7e87956..701d6cd 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -336,6 +336,26 @@
 	return a
 }
 
+// actionList returns the list of actions in the dag rooted at root
+// as visited in a depth-first post-order traversal.
+func actionList(root *action) []*action {
+	seen := map[*action]bool{}
+	all := []*action{}
+	var walk func(*action)
+	walk = func(a *action) {
+		if seen[a] {
+			return
+		}
+		seen[a] = true
+		for _, a1 := range a.deps {
+			walk(a1)
+		}
+		all = append(all, a)
+	}
+	walk(root)
+	return all
+}
+
 // do runs the action graph rooted at root.
 func (b *builder) do(root *action) {
 	// Build list of all actions, assigning depth-first post-order priority.
@@ -349,27 +369,16 @@
 	// ensure that, all else being equal, the execution prefers
 	// to do what it would have done first in a simple depth-first
 	// dependency order traversal.
-	all := map[*action]bool{}
-	priority := 0
-	var walk func(*action)
-	walk = func(a *action) {
-		if all[a] {
-			return
-		}
-		all[a] = true
-		priority++
-		for _, a1 := range a.deps {
-			walk(a1)
-		}
-		a.priority = priority
+	all := actionList(root)
+	for i, a := range all {
+		a.priority = i
 	}
-	walk(root)
 
 	b.readySema = make(chan bool, len(all))
 	done := make(chan bool)
 
 	// Initialize per-action execution state.
-	for a := range all {
+	for _, a := range all {
 		for _, a1 := range a.deps {
 			a1.triggers = append(a1.triggers, a)
 		}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 8f0f59c..f3f79b6 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -48,6 +48,7 @@
 	imports []*Package
 	gofiles []string // GoFiles+CgoFiles, absolute paths
 	target  string   // installed file for this package (may be executable)
+	fake    bool     // synthesized package
 }
 
 // packageCache is a lookup cache for loadPackage,
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index e43a271..4904703 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -193,25 +193,28 @@
 // For now just use the gotest code.
 
 var (
-	testC     bool     // -c flag
-	testX     bool     // -x flag
-	testFiles []string // -file flag(s)  TODO: not respected
-	testArgs  []string
+	testC        bool     // -c flag
+	testX        bool     // -x flag
+	testV        bool     // -v flag
+	testFiles    []string // -file flag(s)  TODO: not respected
+	testArgs     []string
+	testShowPass bool // whether to display passing output
 )
 
 func runTest(cmd *Command, args []string) {
-	// Determine which are the import paths
-	// (leading arguments not starting with -).
-	i := 0
-	for i < len(args) && !strings.HasPrefix(args[i], "-") {
-		i++
-	}
-	pkgs := packages(args[:i])
+	var pkgArgs []string
+	pkgArgs, testArgs = testFlags(args)
+
+	// show test PASS output when no packages
+	// are listed (implicitly current directory: "go test")
+	// or when the -v flag has been given.
+	testShowPass = len(pkgArgs) == 0 || testV
+
+	pkgs := packages(pkgArgs)
 	if len(pkgs) == 0 {
 		fatalf("no packages to test")
 	}
 
-	testArgs = testFlags(args[i:])
 	if testC && len(pkgs) != 1 {
 		fatalf("cannot use -c flag with multiple packages")
 	}
@@ -243,9 +246,31 @@
 			a.deps = append(a.deps, runs[i-1])
 		}
 	}
+	root := &action{deps: runs}
 
-	allRuns := &action{deps: runs}
-	b.do(allRuns)
+	// If we are building any out-of-date packages other
+	// than those under test, warn.
+	okBuild := map[*Package]bool{}
+	for _, p := range pkgs {
+		okBuild[p] = true
+	}
+
+	warned := false
+	for _, a := range actionList(root) {
+		if a.p != nil && a.f != nil && !okBuild[a.p] && !a.p.fake {
+			okBuild[a.p] = true // don't warn again
+			if !warned {
+				fmt.Fprintf(os.Stderr, "warning: building out-of-date packages:\n")
+				warned = true
+			}
+			fmt.Fprintf(os.Stderr, "\t%s\n", a.p.ImportPath)
+		}
+	}
+	if warned {
+		fmt.Fprintf(os.Stderr, "installing these packages with 'go install' will speed future tests.\n\n")
+	}
+
+	b.do(root)
 }
 
 func (b *builder) test(p *Package) (buildAction, runAction *action, err error) {
@@ -312,6 +337,7 @@
 		ptest.Imports = append(append([]string{}, p.info.Imports...), p.info.TestImports...)
 		ptest.imports = append(append([]*Package{}, p.imports...), imports...)
 		ptest.pkgdir = testDir
+		ptest.fake = true
 		a := b.action(modeBuild, modeBuild, ptest)
 		a.objdir = testDir + string(filepath.Separator)
 		a.objpkg = ptestObj
@@ -333,6 +359,7 @@
 			info:       &build.DirInfo{},
 			imports:    imports,
 			pkgdir:     testDir,
+			fake:       true,
 		}
 		pxtest.imports = append(pxtest.imports, ptest)
 		a := b.action(modeBuild, modeBuild, pxtest)
@@ -349,6 +376,7 @@
 		t:       p.t,
 		info:    &build.DirInfo{},
 		imports: []*Package{ptest},
+		fake:    true,
 	}
 	if pxtest != nil {
 		pmain.imports = append(pmain.imports, pxtest)
@@ -407,6 +435,9 @@
 	out, err := cmd.CombinedOutput()
 	if err == nil && (bytes.Equal(out, pass[1:]) || bytes.HasSuffix(out, pass)) {
 		fmt.Printf("ok  \t%s\n", a.p.ImportPath)
+		if testShowPass {
+			os.Stdout.Write(out)
+		}
 		return nil
 	}
 
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index 249a931..0713303 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -78,10 +78,39 @@
 // Unfortunately for us, we need to do our own flag processing because go test
 // grabs some flags but otherwise its command line is just a holding place for
 // test.out's arguments.
-func testFlags(args []string) (passToTest []string) {
+// We allow known flags both before and after the package name list,
+// to allow both
+//	go test fmt -custom-flag-for-fmt-test
+//	go test -x math
+func testFlags(args []string) (packageNames, passToTest []string) {
+	inPkg := false
 	for i := 0; i < len(args); i++ {
+		if !strings.HasPrefix(args[i], "-") {
+			if !inPkg && packageNames == nil {
+				// First package name we've seen.
+				inPkg = true
+			}
+			if inPkg {
+				packageNames = append(packageNames, args[i])
+				continue
+			}
+		}
+
+		if inPkg {
+			// Found an argument beginning with "-"; end of package list.
+			inPkg = false
+		}
+
 		f, value, extraWord := testFlag(args, i)
 		if f == nil {
+			// This is a flag we do not know; we must assume
+			// that any args we see after this might be flag 
+			// arguments, not package names.
+			inPkg = false
+			if packageNames == nil {
+				// make non-nil: we have seen the empty package list
+				packageNames = []string{}
+			}
 			passToTest = append(passToTest, args[i])
 			continue
 		}
@@ -90,6 +119,8 @@
 			setBoolFlag(&testC, value)
 		case "x":
 			setBoolFlag(&testX, value)
+		case "v":
+			setBoolFlag(&testV, value)
 		case "file":
 			testFiles = append(testFiles, value)
 		}