Commit e53a2c40 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

cmd/api: add more tests

Feature extraction was tested before, but not the final diffs.

This CL breaks function main into a smaller main + testable
compareAPI.

No functional changes.

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/6820057
parent 1d61c9bb
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"go/parser" "go/parser"
"go/printer" "go/printer"
"go/token" "go/token"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
...@@ -167,7 +168,6 @@ func main() { ...@@ -167,7 +168,6 @@ func main() {
features = append(features, f2) features = append(features, f2)
} }
} }
sort.Strings(features)
fail := false fail := false
defer func() { defer func() {
...@@ -186,25 +186,26 @@ func main() { ...@@ -186,25 +186,26 @@ func main() {
return return
} }
var required []string required := fileFeatures(*checkFile)
for _, filename := range []string{*checkFile} { optional := fileFeatures(*nextFile)
required = append(required, fileFeatures(filename)...) exception := fileFeatures(*exceptFile)
} fail = !compareAPI(bw, features, required, optional, exception)
sort.Strings(required) }
var optional = make(map[string]bool) // feature => true func compareAPI(w io.Writer, features, required, optional, exception []string) (ok bool) {
if *nextFile != "" { ok = true
for _, feature := range fileFeatures(*nextFile) {
optional[feature] = true
}
}
var exception = make(map[string]bool) // exception => true var optionalSet = make(map[string]bool) // feature => true
if *exceptFile != "" { var exceptionSet = make(map[string]bool) // exception => true
for _, feature := range fileFeatures(*exceptFile) { for _, f := range optional {
exception[feature] = true optionalSet[f] = true
}
} }
for _, f := range exception {
exceptionSet[f] = true
}
sort.Strings(features)
sort.Strings(required)
take := func(sl *[]string) string { take := func(sl *[]string) string {
s := (*sl)[0] s := (*sl)[0]
...@@ -216,23 +217,23 @@ func main() { ...@@ -216,23 +217,23 @@ func main() {
switch { switch {
case len(features) == 0 || required[0] < features[0]: case len(features) == 0 || required[0] < features[0]:
feature := take(&required) feature := take(&required)
if exception[feature] { if exceptionSet[feature] {
fmt.Fprintf(bw, "~%s\n", feature) fmt.Fprintf(w, "~%s\n", feature)
} else { } else {
fmt.Fprintf(bw, "-%s\n", feature) fmt.Fprintf(w, "-%s\n", feature)
fail = true // broke compatibility ok = false // broke compatibility
} }
case len(required) == 0 || required[0] > features[0]: case len(required) == 0 || required[0] > features[0]:
newFeature := take(&features) newFeature := take(&features)
if optional[newFeature] { if optionalSet[newFeature] {
// Known added feature to the upcoming release. // Known added feature to the upcoming release.
// Delete it from the map so we can detect any upcoming features // Delete it from the map so we can detect any upcoming features
// which were never seen. (so we can clean up the nextFile) // which were never seen. (so we can clean up the nextFile)
delete(optional, newFeature) delete(optionalSet, newFeature)
} else { } else {
fmt.Fprintf(bw, "+%s\n", newFeature) fmt.Fprintf(w, "+%s\n", newFeature)
if !*allowNew { if !*allowNew {
fail = true // we're in lock-down mode for next release ok = false // we're in lock-down mode for next release
} }
} }
default: default:
...@@ -243,16 +244,20 @@ func main() { ...@@ -243,16 +244,20 @@ func main() {
// In next file, but not in API. // In next file, but not in API.
var missing []string var missing []string
for feature := range optional { for feature := range optionalSet {
missing = append(missing, feature) missing = append(missing, feature)
} }
sort.Strings(missing) sort.Strings(missing)
for _, feature := range missing { for _, feature := range missing {
fmt.Fprintf(bw, "±%s\n", feature) fmt.Fprintf(w, "±%s\n", feature)
} }
return
} }
func fileFeatures(filename string) []string { func fileFeatures(filename string) []string {
if filename == "" {
return nil
}
bs, err := ioutil.ReadFile(filename) bs, err := ioutil.ReadFile(filename)
if err != nil { if err != nil {
log.Fatalf("Error reading file %s: %v", filename, err) log.Fatalf("Error reading file %s: %v", filename, err)
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package main package main
import ( import (
"bytes"
"flag" "flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
...@@ -73,3 +74,53 @@ func TestGolden(t *testing.T) { ...@@ -73,3 +74,53 @@ func TestGolden(t *testing.T) {
} }
} }
} }
func TestCompareAPI(t *testing.T) {
tests := []struct {
name string
features, required, optional, exception []string
ok bool // want
out string // want
}{
{
name: "feature added",
features: []string{"C", "A", "B"},
required: []string{"A", "C"},
ok: true,
out: "+B\n",
},
{
name: "feature removed",
features: []string{"C", "A"},
required: []string{"A", "B", "C"},
ok: false,
out: "-B\n",
},
{
name: "feature added then removed",
features: []string{"A", "C"},
optional: []string{"B"},
required: []string{"A", "C"},
ok: true,
out: "±B\n",
},
{
name: "exception removal",
required: []string{"A", "B", "C"},
features: []string{"A", "C"},
exception: []string{"B"},
ok: true,
out: "~B\n",
},
}
for _, tt := range tests {
buf := new(bytes.Buffer)
gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception)
if gotok != tt.ok {
t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
}
if got := buf.String(); got != tt.out {
t.Errorf("%s: output differs\nGOT:\n%s\nWANT:\n%s", tt.name, got, tt.out)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment