Ejemplo n.º 1
0
// Simplifying wrapper around buildutil.FakeContext for single-file packages.
func fakeContext(pkgs map[string]string) *build.Context {
	pkgs2 := make(map[string]map[string]string)
	for path, content := range pkgs {
		pkgs2[path] = map[string]string{"x.go": content}
	}
	return buildutil.FakeContext(pkgs2)
}
Ejemplo n.º 2
0
func TestBundle(t *testing.T) {
	load := func(name string) string {
		data, err := ioutil.ReadFile(name)
		if err != nil {
			t.Fatal(err)
		}
		return string(data)
	}

	ctxt = buildutil.FakeContext(map[string]map[string]string{
		"initial": {
			"a.go": load("testdata/src/initial/a.go"),
			"b.go": load("testdata/src/initial/b.go"),
		},
		"fmt": {
			"print.go": `package fmt; func Println(...interface{})`,
		},
	})

	var out bytes.Buffer
	if err := bundle(&out, "initial", "dest", "prefix"); err != nil {
		t.Fatal(err)
	}
	if got, want := out.String(), load("testdata/out.golden"); got != want {
		t.Errorf("-- got --\n%s\n-- want --\n%s\n-- diff --", got, want)

		if err := ioutil.WriteFile("testdata/out.got", out.Bytes(), 0644); err != nil {
			t.Fatal(err)
		}
		t.Log(diff("testdata/out.got", "testdata/out.golden"))
	}
}
Ejemplo n.º 3
0
// Simplifying wrapper around buildutil.FakeContext for packages whose
// filenames are sequentially numbered (%d.go).  pkgs maps a package
// import path to its list of file contents.
func fakeContext(pkgs map[string][]string) *build.Context {
	pkgs2 := make(map[string]map[string]string)
	for path, files := range pkgs {
		filemap := make(map[string]string)
		for i, contents := range files {
			filemap[fmt.Sprintf("%d.go", i)] = contents
		}
		pkgs2[path] = filemap
	}
	return buildutil.FakeContext(pkgs2)
}
Ejemplo n.º 4
0
// Simplifying wrapper around buildutil.FakeContext for packages whose
// filenames are sequentially numbered (%d.go).  pkgs maps a package
// import path to its list of file contents.
func fakeContext(pkgs map[string][]string) *build.Context {
	pkgs["fmt"] = []string{`package fmt; func Println(args ...interface{}) {}`}
	pkgs["io"] = []string{`package io; type Reader interface { Read(p []byte) (n int, err error); }`}
	pkgs2 := make(map[string]map[string]string)
	for path, files := range pkgs {
		filemap := make(map[string]string)
		for i, contents := range files {
			filemap[fmt.Sprintf("%d.go", i)] = contents
		}
		pkgs2[path] = filemap
	}
	return buildutil.FakeContext(pkgs2)
}
Ejemplo n.º 5
0
func TestExpandPatterns(t *testing.T) {
	tree := make(map[string]map[string]string)
	for _, pkg := range []string{
		"encoding",
		"encoding/xml",
		"encoding/hex",
		"encoding/json",
		"fmt",
	} {
		tree[pkg] = make(map[string]string)
	}
	ctxt := buildutil.FakeContext(tree)

	for _, test := range []struct {
		patterns string
		want     string
	}{
		{"", ""},
		{"fmt", "fmt"},
		{"nosuchpkg", "nosuchpkg"},
		{"nosuchdir/...", ""},
		{"...", "encoding encoding/hex encoding/json encoding/xml fmt"},
		{"encoding/... -encoding/xml", "encoding encoding/hex encoding/json"},
		{"... -encoding/...", "fmt"},
		{"encoding", "encoding"},
		{"encoding/", "encoding"},
	} {
		var pkgs []string
		for pkg := range buildutil.ExpandPatterns(ctxt, strings.Fields(test.patterns)) {
			pkgs = append(pkgs, pkg)
		}
		sort.Strings(pkgs)
		got := strings.Join(pkgs, " ")
		if got != test.want {
			t.Errorf("ExpandPatterns(%s) = %s, want %s",
				test.patterns, got, test.want)
		}
	}
}
Ejemplo n.º 6
0
func TestBundle(t *testing.T) {
	load := func(name string) string {
		data, err := ioutil.ReadFile(name)
		if err != nil {
			t.Fatal(err)
		}
		return string(data)
	}

	ctxt = buildutil.FakeContext(map[string]map[string]string{
		"initial": {
			"a.go": load("testdata/src/initial/a.go"),
			"b.go": load("testdata/src/initial/b.go"),
			"c.go": load("testdata/src/initial/c.go"),
		},
		"domain.name/importdecl": {
			"p.go": load("testdata/src/domain.name/importdecl/p.go"),
		},
		"fmt": {
			"print.go": `package fmt; func Println(...interface{})`,
		},
	})

	os.Args = os.Args[:1] // avoid e.g. -test=short in the output
	out, err := bundle("initial", "github.com/dest", "dest", "prefix")
	if err != nil {
		t.Fatal(err)
	}
	if got, want := string(out), load("testdata/out.golden"); got != want {
		t.Errorf("-- got --\n%s\n-- want --\n%s\n-- diff --", got, want)

		if err := ioutil.WriteFile("testdata/out.got", out, 0644); err != nil {
			t.Fatal(err)
		}
		t.Log(diff("testdata/out.golden", "testdata/out.got"))
	}
}
Ejemplo n.º 7
0
func TestCycles(t *testing.T) {
	for _, test := range []struct {
		descr   string
		ctxt    *build.Context
		wantErr string
	}{
		{
			"self-cycle",
			fakeContext(map[string]string{
				"main":      `package main; import _ "selfcycle"`,
				"selfcycle": `package selfcycle; import _ "selfcycle"`,
			}),
			`import cycle: selfcycle -> selfcycle`,
		},
		{
			"three-package cycle",
			fakeContext(map[string]string{
				"main": `package main; import _ "a"`,
				"a":    `package a; import _ "b"`,
				"b":    `package b; import _ "c"`,
				"c":    `package c; import _ "a"`,
			}),
			`import cycle: c -> a -> b -> c`,
		},
		{
			"self-cycle in dependency of test file",
			buildutil.FakeContext(map[string]map[string]string{
				"main": {
					"main.go":      `package main`,
					"main_test.go": `package main; import _ "a"`,
				},
				"a": {
					"a.go": `package a; import _ "a"`,
				},
			}),
			`import cycle: a -> a`,
		},
		// TODO(adonovan): fix: these fail
		// {
		// 	"two-package cycle in dependency of test file",
		// 	buildutil.FakeContext(map[string]map[string]string{
		// 		"main": {
		// 			"main.go":      `package main`,
		// 			"main_test.go": `package main; import _ "a"`,
		// 		},
		// 		"a": {
		// 			"a.go": `package a; import _ "main"`,
		// 		},
		// 	}),
		// 	`import cycle: main -> a -> main`,
		// },
		// {
		// 	"self-cycle in augmented package",
		// 	buildutil.FakeContext(map[string]map[string]string{
		// 		"main": {
		// 			"main.go":      `package main`,
		// 			"main_test.go": `package main; import _ "main"`,
		// 		},
		// 	}),
		// 	`import cycle: main -> main`,
		// },
	} {
		conf := loader.Config{
			AllowErrors: true,
			Build:       test.ctxt,
		}
		var mu sync.Mutex
		var allErrors []error
		conf.TypeChecker.Error = func(err error) {
			mu.Lock()
			allErrors = append(allErrors, err)
			mu.Unlock()
		}
		conf.ImportWithTests("main")

		prog, err := conf.Load()
		if err != nil {
			t.Errorf("%s: Load failed: %s", test.descr, err)
		}
		if prog == nil {
			t.Fatalf("%s: Load returned nil *Program", test.descr)
		}

		if !hasError(allErrors, test.wantErr) {
			t.Errorf("%s: Load() errors = %q, want %q",
				test.descr, allErrors, test.wantErr)
		}
	}

	// TODO(adonovan):
	// - Test that in a legal test cycle, none of the symbols
	//   defined by augmentation are visible via import.
}
Ejemplo n.º 8
0
func TestMoves(t *testing.T) {
	tests := []struct {
		ctxt     *build.Context
		from, to string
		want     map[string]string
	}{
		// Simple example.
		{
			ctxt: fakeContext(map[string][]string{
				"foo": {`package foo; type T int`},
				"main": {`package main

import "foo"

var _ foo.T
`},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/main/0.go": `package main

import "bar"

var _ bar.T
`,
				"/go/src/bar/0.go": `package bar

type T int
`,
			},
		},

		// Example with subpackage.
		{
			ctxt: fakeContext(map[string][]string{
				"foo":     {`package foo; type T int`},
				"foo/sub": {`package sub; type T int`},
				"main": {`package main

import "foo"
import "foo/sub"

var _ foo.T
var _ sub.T
`},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/main/0.go": `package main

import "bar"
import "bar/sub"

var _ bar.T
var _ sub.T
`,
				"/go/src/bar/0.go": `package bar

type T int
`,
				"/go/src/bar/sub/0.go": `package sub; type T int`,
			},
		},

		// References into subpackages
		{
			ctxt: fakeContext(map[string][]string{
				"foo":   {`package foo; import "foo/a"; var _ a.T`},
				"foo/a": {`package a; type T int`},
				"foo/b": {`package b; import "foo/a"; var _ a.T`},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/bar/0.go": `package bar

import "bar/a"

var _ a.T
`,
				"/go/src/bar/a/0.go": `package a; type T int`,
				"/go/src/bar/b/0.go": `package b

import "bar/a"

var _ a.T
`,
			},
		},

		// External test packages
		{
			ctxt: buildutil.FakeContext(map[string]map[string]string{
				"foo": {
					"0.go":      `package foo; type T int`,
					"0_test.go": `package foo_test; import "foo"; var _ foo.T`,
				},
				"baz": {
					"0_test.go": `package baz_test; import "foo"; var _ foo.T`,
				},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/bar/0.go": `package bar

type T int
`,
				"/go/src/bar/0_test.go": `package bar_test

import "bar"

var _ bar.T
`,
				"/go/src/baz/0_test.go": `package baz_test

import "bar"

var _ bar.T
`,
			},
		},
	}

	for _, test := range tests {
		ctxt := test.ctxt

		got := make(map[string]string)
		// Populate got with starting file set. rewriteFile and moveDirectory
		// will mutate got to produce resulting file set.
		buildutil.ForEachPackage(ctxt, func(importPath string, err error) {
			if err != nil {
				return
			}
			path := filepath.Join("/go/src", importPath, "0.go")
			if !buildutil.FileExists(ctxt, path) {
				return
			}
			f, err := ctxt.OpenFile(path)
			if err != nil {
				t.Errorf("unexpected error opening file: %s", err)
				return
			}
			bytes, err := ioutil.ReadAll(f)
			f.Close()
			if err != nil {
				t.Errorf("unexpected error reading file: %s", err)
				return
			}
			got[path] = string(bytes)
		})
		rewriteFile = func(fset *token.FileSet, f *ast.File, orig string) error {
			var out bytes.Buffer
			if err := format.Node(&out, fset, f); err != nil {
				return err
			}
			got[orig] = out.String()
			return nil
		}
		moveDirectory = func(from, to string) error {
			for path, contents := range got {
				if strings.HasPrefix(path, from) {
					newPath := strings.Replace(path, from, to, 1)
					delete(got, path)
					got[newPath] = contents
				}
			}
			return nil
		}

		err := Move(ctxt, test.from, test.to, "")
		prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
		if err != nil {
			t.Errorf("%s: unexpected error: %s", prefix, err)
			continue
		}

		for file, wantContent := range test.want {
			k := filepath.FromSlash(file)
			gotContent, ok := got[k]
			delete(got, k)
			if !ok {
				// TODO(matloob): some testcases might have files that won't be
				// rewritten
				t.Errorf("%s: file %s not rewritten", prefix, file)
				continue
			}
			if gotContent != wantContent {
				t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
					"want <<<%s>>>", prefix, file, gotContent, wantContent)
			}
		}
		// got should now be empty
		for file := range got {
			t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
		}
	}
}
Ejemplo n.º 9
0
func TestMoves(t *testing.T) {
	if runtime.GOOS == "windows" {
		t.Skip("broken on Windows; see golang.org/issue/16384")
	}
	tests := []struct {
		ctxt         *build.Context
		from, to     string
		want         map[string]string
		wantWarnings []string
	}{
		// Simple example.
		{
			ctxt: fakeContext(map[string][]string{
				"foo": {`package foo; type T int`},
				"main": {`package main

import "foo"

var _ foo.T
`},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/main/0.go": `package main

import "bar"

var _ bar.T
`,
				"/go/src/bar/0.go": `package bar

type T int
`,
			},
		},

		// Example with subpackage.
		{
			ctxt: fakeContext(map[string][]string{
				"foo":     {`package foo; type T int`},
				"foo/sub": {`package sub; type T int`},
				"main": {`package main

import "foo"
import "foo/sub"

var _ foo.T
var _ sub.T
`},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/main/0.go": `package main

import "bar"
import "bar/sub"

var _ bar.T
var _ sub.T
`,
				"/go/src/bar/0.go": `package bar

type T int
`,
				"/go/src/bar/sub/0.go": `package sub; type T int`,
			},
		},

		// References into subpackages
		{
			ctxt: fakeContext(map[string][]string{
				"foo":   {`package foo; import "foo/a"; var _ a.T`},
				"foo/a": {`package a; type T int`},
				"foo/b": {`package b; import "foo/a"; var _ a.T`},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/bar/0.go": `package bar

import "bar/a"

var _ a.T
`,
				"/go/src/bar/a/0.go": `package a; type T int`,
				"/go/src/bar/b/0.go": `package b

import "bar/a"

var _ a.T
`,
			},
		},

		// External test packages
		{
			ctxt: buildutil.FakeContext(map[string]map[string]string{
				"foo": {
					"0.go":      `package foo; type T int`,
					"0_test.go": `package foo_test; import "foo"; var _ foo.T`,
				},
				"baz": {
					"0_test.go": `package baz_test; import "foo"; var _ foo.T`,
				},
			}),
			from: "foo", to: "bar",
			want: map[string]string{
				"/go/src/bar/0.go": `package bar

type T int
`,
				"/go/src/bar/0_test.go": `package bar_test

import "bar"

var _ bar.T
`,
				"/go/src/baz/0_test.go": `package baz_test

import "bar"

var _ bar.T
`,
			},
		},
		// package import comments
		{
			ctxt: fakeContext(map[string][]string{"foo": {`package foo // import "baz"`}}),
			from: "foo", to: "bar",
			want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
`},
		},
		{
			ctxt: fakeContext(map[string][]string{"foo": {`package foo /* import "baz" */`}}),
			from: "foo", to: "bar",
			want: map[string]string{"/go/src/bar/0.go": `package bar /* import "bar" */
`},
		},
		{
			ctxt: fakeContext(map[string][]string{"foo": {`package foo       // import "baz"`}}),
			from: "foo", to: "bar",
			want: map[string]string{"/go/src/bar/0.go": `package bar // import "bar"
`},
		},
		{
			ctxt: fakeContext(map[string][]string{"foo": {`package foo
// import " this is not an import comment`}}),
			from: "foo", to: "bar",
			want: map[string]string{"/go/src/bar/0.go": `package bar

// import " this is not an import comment
`},
		},
		{
			ctxt: fakeContext(map[string][]string{"foo": {`package foo
/* import " this is not an import comment */`}}),
			from: "foo", to: "bar",
			want: map[string]string{"/go/src/bar/0.go": `package bar

/* import " this is not an import comment */
`},
		},
		// Import name conflict generates a warning, not an error.
		{
			ctxt: fakeContext(map[string][]string{
				"x": {},
				"a": {`package a; type A int`},
				"b": {`package b; type B int`},
				"conflict": {`package conflict

import "a"
import "b"
var _ a.A
var _ b.B
`},
				"ok": {`package ok
import "b"
var _ b.B
`},
			}),
			from: "b", to: "x/a",
			want: map[string]string{
				"/go/src/a/0.go": `package a; type A int`,
				"/go/src/ok/0.go": `package ok

import "x/a"

var _ a.B
`,
				"/go/src/conflict/0.go": `package conflict

import "a"
import "x/a"

var _ a.A
var _ b.B
`,
				"/go/src/x/a/0.go": `package a

type B int
`,
			},
			wantWarnings: []string{
				`/go/src/conflict/0.go:4:8: renaming this imported package name "b" to "a"`,
				`/go/src/conflict/0.go:3:8: 	conflicts with imported package name in same block`,
				`/go/src/conflict/0.go:3:8: skipping update of this file`,
			},
		},
		// Rename with same base name.
		{
			ctxt: fakeContext(map[string][]string{
				"x": {},
				"y": {},
				"x/foo": {`package foo

type T int
`},
				"main": {`package main; import "x/foo"; var _ foo.T`},
			}),
			from: "x/foo", to: "y/foo",
			want: map[string]string{
				"/go/src/y/foo/0.go": `package foo

type T int
`,
				"/go/src/main/0.go": `package main

import "y/foo"

var _ foo.T
`,
			},
		},
	}

	for _, test := range tests {
		ctxt := test.ctxt

		got := make(map[string]string)
		// Populate got with starting file set. rewriteFile and moveDirectory
		// will mutate got to produce resulting file set.
		buildutil.ForEachPackage(ctxt, func(importPath string, err error) {
			if err != nil {
				return
			}
			path := filepath.Join("/go/src", importPath, "0.go")
			if !buildutil.FileExists(ctxt, path) {
				return
			}
			f, err := ctxt.OpenFile(path)
			if err != nil {
				t.Errorf("unexpected error opening file: %s", err)
				return
			}
			bytes, err := ioutil.ReadAll(f)
			f.Close()
			if err != nil {
				t.Errorf("unexpected error reading file: %s", err)
				return
			}
			got[path] = string(bytes)
		})
		var warnings []string
		reportError = func(posn token.Position, message string) {
			warning := fmt.Sprintf("%s:%d:%d: %s",
				filepath.ToSlash(posn.Filename), // for MS Windows
				posn.Line,
				posn.Column,
				message)
			warnings = append(warnings, warning)

		}
		writeFile = func(filename string, content []byte) error {
			got[filename] = string(content)
			return nil
		}
		moveDirectory = func(from, to string) error {
			for path, contents := range got {
				if strings.HasPrefix(path, from) {
					newPath := strings.Replace(path, from, to, 1)
					delete(got, path)
					got[newPath] = contents
				}
			}
			return nil
		}

		err := Move(ctxt, test.from, test.to, "")
		prefix := fmt.Sprintf("-from %q -to %q", test.from, test.to)
		if err != nil {
			t.Errorf("%s: unexpected error: %s", prefix, err)
			continue
		}

		if !reflect.DeepEqual(warnings, test.wantWarnings) {
			t.Errorf("%s: unexpected warnings:\n%s\nwant:\n%s",
				prefix,
				strings.Join(warnings, "\n"),
				strings.Join(test.wantWarnings, "\n"))
		}

		for file, wantContent := range test.want {
			k := filepath.FromSlash(file)
			gotContent, ok := got[k]
			delete(got, k)
			if !ok {
				// TODO(matloob): some testcases might have files that won't be
				// rewritten
				t.Errorf("%s: file %s not rewritten", prefix, file)
				continue
			}
			if gotContent != wantContent {
				t.Errorf("%s: rewritten file %s does not match expectation; got <<<%s>>>\n"+
					"want <<<%s>>>", prefix, file, gotContent, wantContent)
			}
		}
		// got should now be empty
		for file := range got {
			t.Errorf("%s: unexpected rewrite of file %s", prefix, file)
		}
	}
}