1
0
mirror of https://github.com/golang/go synced 2024-10-01 13:18:33 -06:00
go/oracle/oracle_test.go

297 lines
7.7 KiB
Go
Raw Normal View History

// Copyright 2013 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 oracle_test
// This file defines a test framework for oracle queries.
//
// The files beneath testdata/src/main contain Go programs containing
// query annotations of the form:
//
// @verb id "select"
//
// where verb is the query mode (e.g. "callers"), id is a unique name
// for this query, and "select" is a regular expression matching the
// substring of the current line that is the query's input selection.
//
// The expected output for each query is provided in the accompanying
// .golden file.
//
// (Location information is not included because it's too fragile to
// display as text. TODO(adonovan): think about how we can test its
// correctness, since it is critical information.)
//
// Run this test with:
// % go test code.google.com/p/go.tools/oracle -update
// to update the golden files.
import (
"bytes"
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
"encoding/json"
"flag"
"fmt"
"go/build"
"go/parser"
"go/token"
"io"
"io/ioutil"
"os"
"os/exec"
"regexp"
"runtime"
"strconv"
"strings"
"testing"
"code.google.com/p/go.tools/importer"
"code.google.com/p/go.tools/oracle"
)
var updateFlag = flag.Bool("update", false, "Update the golden files.")
type query struct {
id string // unique id
verb string // query mode, e.g. "callees"
posn token.Position // position of of query
filename string
start, end int // selection of file to pass to oracle
}
func parseRegexp(text string) (*regexp.Regexp, error) {
pattern, err := strconv.Unquote(text)
if err != nil {
return nil, fmt.Errorf("can't unquote %s", text)
}
return regexp.Compile(pattern)
}
// parseQueries parses and returns the queries in the named file.
func parseQueries(t *testing.T, filename string) []*query {
filedata, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatal(err)
}
// Parse the file once to discover the test queries.
var fset token.FileSet
f, err := parser.ParseFile(&fset, filename, filedata, parser.ParseComments)
if err != nil {
t.Fatal(err)
}
lines := bytes.Split(filedata, []byte("\n"))
var queries []*query
queriesById := make(map[string]*query)
// Find all annotations of these forms:
expectRe := regexp.MustCompile(`@([a-z]+)\s+(\S+)\s+(\".*)$`) // @verb id "regexp"
for _, c := range f.Comments {
text := strings.TrimSpace(c.Text())
if text == "" || text[0] != '@' {
continue
}
posn := fset.Position(c.Pos())
// @verb id "regexp"
match := expectRe.FindStringSubmatch(text)
if match == nil {
t.Errorf("%s: ill-formed query: %s", posn, text)
continue
}
id := match[2]
if prev, ok := queriesById[id]; ok {
t.Errorf("%s: duplicate id %s", posn, id)
t.Errorf("%s: previously used here", prev.posn)
continue
}
selectRe, err := parseRegexp(match[3])
if err != nil {
t.Errorf("%s: %s", posn, err)
continue
}
// Find text of the current line, sans query.
// (Queries must be // not /**/ comments.)
line := lines[posn.Line-1][:posn.Column-1]
// Apply regexp to current line to find input selection.
loc := selectRe.FindIndex(line)
if loc == nil {
t.Errorf("%s: selection pattern %s doesn't match line %q",
posn, match[3], string(line))
continue
}
// Assumes ASCII. TODO(adonovan): test on UTF-8.
linestart := posn.Offset - (posn.Column - 1)
// Compute the file offsets
q := &query{
id: id,
verb: match[1],
posn: posn,
filename: filename,
start: linestart + loc[0],
end: linestart + loc[1],
}
queries = append(queries, q)
queriesById[id] = q
}
// Return the slice, not map, for deterministic iteration.
return queries
}
// WriteResult writes res (-format=plain) to w, stripping file locations.
func WriteResult(w io.Writer, res *oracle.Result) {
capture := new(bytes.Buffer) // capture standard output
res.WriteTo(capture)
for _, line := range strings.Split(capture.String(), "\n") {
// Remove a "file:line: " prefix.
if i := strings.Index(line, ": "); i >= 0 {
line = line[i+2:]
}
fmt.Fprintf(w, "%s\n", line)
}
}
// doQuery poses query q to the oracle and writes its response and
// error (if any) to out.
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
func doQuery(out io.Writer, q *query, useJson bool) {
fmt.Fprintf(out, "-------- @%s %s --------\n", q.verb, q.id)
var buildContext = build.Default
buildContext.GOPATH = "testdata"
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
res, err := oracle.Query([]string{q.filename},
q.verb,
fmt.Sprintf("%s:#%d,#%d", q.filename, q.start, q.end),
nil, // ptalog,
&buildContext,
true) // reflection
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
if err != nil {
fmt.Fprintf(out, "\nError: %s\n", err)
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
return
}
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
if useJson {
// JSON output
b, err := json.MarshalIndent(res.Serial(), "", "\t")
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
if err != nil {
fmt.Fprintf(out, "JSON error: %s\n", err.Error())
return
}
out.Write(b)
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
} else {
// "plain" (compiler diagnostic format) output
WriteResult(out, res)
}
}
func TestOracle(t *testing.T) {
switch runtime.GOOS {
case "windows":
t.Skipf("skipping test on %q (no /usr/bin/diff)", runtime.GOOS)
}
for _, filename := range []string{
"testdata/src/main/calls.go",
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
"testdata/src/main/callgraph.go",
go.tools/ssa: fix computation of set of types requiring method sets. Motivation: Previously, we assumed that the set of types for which a complete method set (containing all synthesized wrapper functions) is required at runtime was the set of types used as operands to some *ssa.MakeInterface instruction. In fact, this is an underapproximation because types can be derived from other ones via reflection, and some of these may need methods. The reflect.Type API allows *T to be derived from T, and these may have different method sets. Reflection also allows almost any subcomponent of a type to be accessed (with one exception: given T, defined 'type T struct{S}', you can reach S but not struct{S}). As a result, the pointer analysis was unable to generate all necessary constraints before running the solver, causing a crash when reflection derives types whose methods are unavailable. (A similar problem would afflict an ahead-of-time compiler based on ssa. The ssa/interp interpreter was immune only because it does not require all wrapper methods to be created before execution begins.) Description: This change causes the SSA builder to record, for each package, the set of all types with non-empty method sets that are referenced within that package. This set is accessed via Packages.TypesWithMethodSets(). Program.TypesWithMethodSets() returns its union across all packages. The set of references that matter are: - types of operands to some MakeInterface instruction (as before) - types of all exported package members - all subcomponents of the above, recursively. This is a conservative approximation to the set of types whose methods may be called dynamically. We define the owning package of a type as follows: - the owner of a named type is the package in which it is defined; - the owner of a pointer-to-named type is the owner of that named type; - the owner of all other types is nil. A package must include the method sets for all types that it owns, and all subcomponents of that type that are not owned by another package, recursively. Types with an owner appear in exactly one package; types with no owner (such as struct{T}) may appear within multiple packages. (A typical Go compiler would emit multiple copies of these methods as weak symbols; a typical linker would eliminate duplicates.) Also: - go/types/typemap: implement hash function for *Tuple. - pointer: generate nodes/constraints for all of ssa.Program.TypesWithMethodSets(). Add rtti.go regression test. - Add API test of Package.TypesWithMethodSets(). - Set Function.Pkg to nil (again) for wrapper functions, since these may be shared by many packages. - Remove a redundant logging statement. - Document that ssa CREATE phase is in fact sequential. Fixes golang/go#6605 R=gri CC=golang-dev https://golang.org/cl/14920056
2013-10-23 15:07:52 -06:00
// "testdata/src/main/callgraph2.go", // TODO(adonovan): make printing deterministic
"testdata/src/main/describe.go",
"testdata/src/main/freevars.go",
"testdata/src/main/implements.go",
"testdata/src/main/imports.go",
"testdata/src/main/peers.go",
go.tools/pointer: reflection, part 1: maps, and some core features. Core: reflect.TypeOf reflect.ValueOf reflect.Zero reflect.Value.Interface Maps: (reflect.Value).MapIndex (reflect.Value).MapKeys (reflect.Value).SetMapIndex (*reflect.rtype).Elem (*reflect.rtype).Key + tests: pointer/testdata/mapreflect.go. oracle/testdata/src/main/reflection.go. Interface objects (T, V...) have been renamed "tagged objects". Abstraction: we model reflect.Value similar to interface{}---as a pointer that points only to tagged objects---but a reflect.Value may also point to an "indirect tagged object", one in which the payload V is of type *T not T. These are required because reflect.Values can hold lvalues, e.g. when derived via Field() or Elem(), though we won't use them till we get to structs and pointers. Solving: each reflection intrinsic defines a new constraint and resolution rule. Because of the nature of reflection, generalizing across types, the resolution rules dynamically create additional complex constraints during solving, where previously only simple (copy) constraints were created. This requires some solver changes: The work done before the main solver loop (to attach new constraints to the graph) is now done before each iteration, in processNewConstraints. Its loop over constraints is broken into two passes: the first handles base (addr-of) constraints, the second handles simple and complex constraints. constraint.init() has been inlined. The only behaviour that varies across constraints is ptr() Sadly this will pessimize presolver optimisations, when we get there; such is the price of reflection. Objects: reflection intrinsics create objects (i.e. cause memory allocations) with no SSA operation. We will represent them as the cgnode of the instrinsic (e.g. reflect.New), so we extend Labels and node.data to represent objects as a product (not sum) of ssa.Value and cgnode and pull this out into its own type, struct object. This simplifies a number of invariants and saves space. The ntObject flag is now represented by obj!=nil; the other flags are moved into object. cgnodes are now always recorded in objects/Labels for which it is appropriate (all but those for globals, constants and the shared contours for functions). Also: - Prepopulate the flattenMemo cache to consider reflect.Value a fake pointer, not a struct. - Improve accessors and documentation on type Label. - @conctypes assertions renamed @types (since dyn. types needn't be concrete). - add oracle 'describe' test on an interface (missing, an oversight). R=crawshaw CC=golang-dev https://golang.org/cl/13418048
2013-09-16 07:49:10 -06:00
"testdata/src/main/reflection.go",
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
// JSON:
"testdata/src/main/callgraph-json.go",
"testdata/src/main/calls-json.go",
"testdata/src/main/peers-json.go",
"testdata/src/main/describe-json.go",
"testdata/src/main/referrers-json.go",
} {
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
useJson := strings.HasSuffix(filename, "-json.go")
queries := parseQueries(t, filename)
golden := filename + "lden"
got := filename + "t"
gotfh, err := os.Create(got)
if err != nil {
t.Errorf("Create(%s) failed: %s", got, err)
continue
}
defer gotfh.Close()
// Run the oracle on each query, redirecting its output
// and error (if any) to the foo.got file.
for _, q := range queries {
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
doQuery(gotfh, q, useJson)
}
// Compare foo.got with foo.golden.
cmd := exec.Command("/usr/bin/diff", "-u", golden, got) // assumes POSIX
buf := new(bytes.Buffer)
cmd.Stdout = buf
if err := cmd.Run(); err != nil {
t.Errorf("Oracle tests for %s failed: %s.\n%s\n",
filename, err, buf)
if *updateFlag {
t.Logf("Updating %s...", golden)
if err := exec.Command("/bin/cp", got, golden).Run(); err != nil {
t.Errorf("Update failed: %s", err)
}
}
}
}
}
func TestMultipleQueries(t *testing.T) {
// Importer
var buildContext = build.Default
buildContext.GOPATH = "testdata"
imp := importer.New(&importer.Config{Build: &buildContext})
// Oracle
filename := "testdata/src/main/multi.go"
o, err := oracle.New(imp, []string{filename}, nil, true)
if err != nil {
t.Fatalf("oracle.New failed: %s", err)
}
// QueryPos
pos := filename + ":#54,#58"
qpos, err := oracle.ParseQueryPos(imp, pos, true)
if err != nil {
t.Fatalf("oracle.ParseQueryPos(%q) failed: %s", pos, err)
}
// SSA is built and we have the QueryPos.
// Release the other ASTs and type info to the GC.
imp = nil
// Run different query modes on same scope and selection.
out := new(bytes.Buffer)
for _, mode := range [...]string{"callers", "describe", "freevars"} {
res, err := o.Query(mode, qpos)
if err != nil {
t.Errorf("(*oracle.Oracle).Query(%q) failed: %s", pos, err)
}
WriteResult(out, res)
}
want := `multi.f is called from these 1 sites:
static function call from multi.main
function call (or conversion) of type ()
Free identifiers:
var x int
`
if got := out.String(); got != want {
t.Errorf("Query output differs; want <<%s>>, got <<%s>>\n", want, got)
}
}