Bump google.golang.org/api

This commit is contained in:
Andrea Spacca
2019-03-17 20:19:56 +01:00
parent 8e39b7fa01
commit ec086b4eb3
5432 changed files with 2486664 additions and 231553 deletions

17
vendor/github.com/golang/mock/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,17 @@
# Object files and binaries from go.
*.[568]
# Library files.
*.a
# Any file prefixed by an underscore.
*/_*
# Vim temporary files.
.*.swp
# The mockgen binary.
mockgen/mockgen
# A binary produced by gotest.
#gomock/[568]\.out

16
vendor/github.com/golang/mock/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,16 @@
language: go
go:
- 1.10.x
- 1.11.x
- 1.12.x
env:
- GO111MODULE=on
script:
- go build ./...
- go install github.com/golang/mock/mockgen
- ./ci/check_go_fmt.sh
- ./ci/check_go_generate.sh
- go test -v ./...

12
vendor/github.com/golang/mock/AUTHORS generated vendored Normal file
View File

@@ -0,0 +1,12 @@
# This is the official list of GoMock authors for copyright purposes.
# This file is distinct from the CONTRIBUTORS files.
# See the latter for an explanation.
# Names should be added to this file as
# Name or Organization <email address>
# The email address is not required for organizations.
# Please keep the list sorted.
Alex Reece <awreece@gmail.com>
Google Inc.

37
vendor/github.com/golang/mock/CONTRIBUTORS generated vendored Normal file
View File

@@ -0,0 +1,37 @@
# This is the official list of people who can contribute (and typically
# have contributed) code to the gomock repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# The submission process automatically checks to make sure
# that people submitting code are listed in this file (by email address).
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# http://code.google.com/legal/individual-cla-v1.0.html
# http://code.google.com/legal/corporate-cla-v1.0.html
#
# The agreement for individuals can be filled out on the web.
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
# Names should be added to this file like so:
# Name <email address>
#
# An entry with two email addresses specifies that the
# first address should be used in the submit logs and
# that the second address should be recognized as the
# same person when interacting with Rietveld.
# Please keep the list sorted.
Aaron Jacobs <jacobsa@google.com> <aaronjjacobs@gmail.com>
Alex Reece <awreece@gmail.com>
David Symonds <dsymonds@golang.org>
Ryan Barrett <ryanb@google.com>

202
vendor/github.com/golang/mock/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

170
vendor/github.com/golang/mock/README.md generated vendored Normal file
View File

@@ -0,0 +1,170 @@
gomock [![Build Status][travis-ci-badge]][travis-ci] [![GoDoc][godoc-badge]][godoc]
======
GoMock is a mocking framework for the [Go programming language][golang]. It
integrates well with Go's built-in `testing` package, but can be used in other
contexts too.
Installation
------------
Once you have [installed Go][golang-install], run these commands
to install the `gomock` package and the `mockgen` tool:
go get github.com/golang/mock/gomock
go install github.com/golang/mock/mockgen
Documentation
-------------
After installing, you can use `go doc` to get documentation:
go doc github.com/golang/mock/gomock
Alternatively, there is an online reference for the package hosted on GoPkgDoc
[here][gomock-ref].
Running mockgen
---------------
`mockgen` has two modes of operation: source and reflect.
Source mode generates mock interfaces from a source file.
It is enabled by using the -source flag. Other flags that
may be useful in this mode are -imports and -aux_files.
Example:
mockgen -source=foo.go [other options]
Reflect mode generates mock interfaces by building a program
that uses reflection to understand interfaces. It is enabled
by passing two non-flag arguments: an import path, and a
comma-separated list of symbols.
Example:
mockgen database/sql/driver Conn,Driver
The `mockgen` command is used to generate source code for a mock
class given a Go source file containing interfaces to be mocked.
It supports the following flags:
* `-source`: A file containing interfaces to be mocked.
* `-destination`: A file to which to write the resulting source code. If you
don't set this, the code is printed to standard output.
* `-package`: The package to use for the resulting mock class
source code. If you don't set this, the package name is `mock_` concatenated
with the package of the input file.
* `-imports`: A list of explicit imports that should be used in the resulting
source code, specified as a comma-separated list of elements of the form
`foo=bar/baz`, where `bar/baz` is the package being imported and `foo` is
the identifier to use for the package in the generated source code.
* `-aux_files`: A list of additional files that should be consulted to
resolve e.g. embedded interfaces defined in a different file. This is
specified as a comma-separated list of elements of the form
`foo=bar/baz.go`, where `bar/baz.go` is the source file and `foo` is the
package name of that file used by the -source file.
* `-build_flags`: (reflect mode only) Flags passed verbatim to `go build`.
* `-mock_names`: A list of custom names for generated mocks. This is specified
as a comma-separated list of elements of the form
`Repository=MockSensorRepository,Endpoint=MockSensorEndpoint`, where
`Repository` is the interface name and `MockSensorRepository` is the desired
mock name (mock factory method and mock recorder will be named after the mock).
If one of the interfaces has no custom name specified, then default naming
convention will be used.
* `-copyright_file`: Copyright file used to add copyright header to the resulting source code.
For an example of the use of `mockgen`, see the `sample/` directory. In simple
cases, you will need only the `-source` flag.
Building Mocks
--------------
```go
type Foo interface {
Bar(x int) int
}
func SUT(f Foo) {
// ...
}
```
```go
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
// Assert that Bar() is invoked.
defer ctrl.Finish()
m := NewMockFoo(ctrl)
// Asserts that the first and only call to Bar() is passed 99.
// Anything else will fail.
m.
EXPECT().
Bar(gomock.Eq(99)).
Return(101)
SUT(m)
}
```
Building Stubs
--------------
```go
type Foo interface {
Bar(x int) int
}
Func SUT(f Foo) {
// ...
}
```
```go
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
m := NewMockFoo(ctrl)
// Does not make any assertions. Returns 101 when Bar is invoked with 99.
m.
EXPECT().
Bar(gomock.Eq(99)).
Return(101).
AnyTimes()
// Does not make any assertions. Returns 103 when Bar is invoked with 101.
m.
EXPECT().
Bar(gomock.Eq(101)).
Return(103).
AnyTimes()
SUT(m)
}
```
[golang]: http://golang.org/
[golang-install]: http://golang.org/doc/install.html#releases
[gomock-ref]: http://godoc.org/github.com/golang/mock/gomock
[travis-ci-badge]: https://travis-ci.org/golang/mock.svg?branch=master
[travis-ci]: https://travis-ci.org/golang/mock
[godoc-badge]: https://godoc.org/github.com/golang/mock/gomock?status.svg
[godoc]: https://godoc.org/github.com/golang/mock/gomock

12
vendor/github.com/golang/mock/ci/check_go_fmt.sh generated vendored Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
# This script is used by the CI to check if the code is gofmt formatted.
set -euo pipefail
GOFMT_DIFF=$(IFS=$'\n'; gofmt -d $( find . -type f -name '*.go' ) )
if [[ -n "${GOFMT_DIFF}" ]]; then
echo "${GOFMT_DIFF}"
echo
echo "The go source files aren't gofmt formatted."
exit 1
fi

25
vendor/github.com/golang/mock/ci/check_go_generate.sh generated vendored Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# This script is used by the CI to check if 'go generate ./...' is up to date.
#
# Note: If the generated files aren't up to date then this script updates
# them despite printing an error message so running it the second time
# might not print any errors. This isn't very useful locally during development
# but it works well with the CI that downloads a fresh version of the repo
# each time before executing this script.
set -euo pipefail
TEMP_DIR=$( mktemp -d )
function cleanup() {
rm -rf "${TEMP_DIR}"
}
trap cleanup EXIT
cp -r . "${TEMP_DIR}/"
go generate ./...
if ! diff -r . "${TEMP_DIR}"; then
echo
echo "The generated files aren't up to date."
echo "Update them with the 'go generate ./...' command."
exit 1
fi

3
vendor/github.com/golang/mock/go.mod generated vendored Normal file
View File

@@ -0,0 +1,3 @@
module github.com/golang/mock
require golang.org/x/tools v0.0.0-20190221204921-83362c3779f5

9
vendor/github.com/golang/mock/go.sum generated vendored Normal file
View File

@@ -0,0 +1,9 @@
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190221204921-83362c3779f5 h1:ev5exjGDsOo0NPTB0qdCcE53BfWl1IICJlhgXgfT9fM=
golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=

420
vendor/github.com/golang/mock/gomock/call.go generated vendored Normal file
View File

@@ -0,0 +1,420 @@
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gomock
import (
"fmt"
"reflect"
"strconv"
"strings"
)
// Call represents an expected call to a mock.
type Call struct {
t TestHelper // for triggering test failures on invalid call setup
receiver interface{} // the receiver of the method call
method string // the name of the method
methodType reflect.Type // the type of the method
args []Matcher // the args
origin string // file and line number of call setup
preReqs []*Call // prerequisite calls
// Expectations
minCalls, maxCalls int
numCalls int // actual number made
// actions are called when this Call is called. Each action gets the args and
// can set the return values by returning a non-nil slice. Actions run in the
// order they are created.
actions []func([]interface{}) []interface{}
}
// newCall creates a *Call. It requires the method type in order to support
// unexported methods.
func newCall(t TestHelper, receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
t.Helper()
// TODO: check arity, types.
margs := make([]Matcher, len(args))
for i, arg := range args {
if m, ok := arg.(Matcher); ok {
margs[i] = m
} else if arg == nil {
// Handle nil specially so that passing a nil interface value
// will match the typed nils of concrete args.
margs[i] = Nil()
} else {
margs[i] = Eq(arg)
}
}
origin := callerInfo(3)
actions := []func([]interface{}) []interface{}{func([]interface{}) []interface{} {
// Synthesize the zero value for each of the return args' types.
rets := make([]interface{}, methodType.NumOut())
for i := 0; i < methodType.NumOut(); i++ {
rets[i] = reflect.Zero(methodType.Out(i)).Interface()
}
return rets
}}
return &Call{t: t, receiver: receiver, method: method, methodType: methodType,
args: margs, origin: origin, minCalls: 1, maxCalls: 1, actions: actions}
}
// AnyTimes allows the expectation to be called 0 or more times
func (c *Call) AnyTimes() *Call {
c.minCalls, c.maxCalls = 0, 1e8 // close enough to infinity
return c
}
// MinTimes requires the call to occur at least n times. If AnyTimes or MaxTimes have not been called, MinTimes also
// sets the maximum number of calls to infinity.
func (c *Call) MinTimes(n int) *Call {
c.minCalls = n
if c.maxCalls == 1 {
c.maxCalls = 1e8
}
return c
}
// MaxTimes limits the number of calls to n times. If AnyTimes or MinTimes have not been called, MaxTimes also
// sets the minimum number of calls to 0.
func (c *Call) MaxTimes(n int) *Call {
c.maxCalls = n
if c.minCalls == 1 {
c.minCalls = 0
}
return c
}
// DoAndReturn declares the action to run when the call is matched.
// The return values from this function are returned by the mocked function.
// It takes an interface{} argument to support n-arity functions.
func (c *Call) DoAndReturn(f interface{}) *Call {
// TODO: Check arity and types here, rather than dying badly elsewhere.
v := reflect.ValueOf(f)
c.addAction(func(args []interface{}) []interface{} {
vargs := make([]reflect.Value, len(args))
ft := v.Type()
for i := 0; i < len(args); i++ {
if args[i] != nil {
vargs[i] = reflect.ValueOf(args[i])
} else {
// Use the zero value for the arg.
vargs[i] = reflect.Zero(ft.In(i))
}
}
vrets := v.Call(vargs)
rets := make([]interface{}, len(vrets))
for i, ret := range vrets {
rets[i] = ret.Interface()
}
return rets
})
return c
}
// Do declares the action to run when the call is matched. The function's
// return values are ignored to retain backward compatibility. To use the
// return values call DoAndReturn.
// It takes an interface{} argument to support n-arity functions.
func (c *Call) Do(f interface{}) *Call {
// TODO: Check arity and types here, rather than dying badly elsewhere.
v := reflect.ValueOf(f)
c.addAction(func(args []interface{}) []interface{} {
vargs := make([]reflect.Value, len(args))
ft := v.Type()
for i := 0; i < len(args); i++ {
if args[i] != nil {
vargs[i] = reflect.ValueOf(args[i])
} else {
// Use the zero value for the arg.
vargs[i] = reflect.Zero(ft.In(i))
}
}
v.Call(vargs)
return nil
})
return c
}
// Return declares the values to be returned by the mocked function call.
func (c *Call) Return(rets ...interface{}) *Call {
c.t.Helper()
mt := c.methodType
if len(rets) != mt.NumOut() {
c.t.Fatalf("wrong number of arguments to Return for %T.%v: got %d, want %d [%s]",
c.receiver, c.method, len(rets), mt.NumOut(), c.origin)
}
for i, ret := range rets {
if got, want := reflect.TypeOf(ret), mt.Out(i); got == want {
// Identical types; nothing to do.
} else if got == nil {
// Nil needs special handling.
switch want.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
// ok
default:
c.t.Fatalf("argument %d to Return for %T.%v is nil, but %v is not nillable [%s]",
i, c.receiver, c.method, want, c.origin)
}
} else if got.AssignableTo(want) {
// Assignable type relation. Make the assignment now so that the generated code
// can return the values with a type assertion.
v := reflect.New(want).Elem()
v.Set(reflect.ValueOf(ret))
rets[i] = v.Interface()
} else {
c.t.Fatalf("wrong type of argument %d to Return for %T.%v: %v is not assignable to %v [%s]",
i, c.receiver, c.method, got, want, c.origin)
}
}
c.addAction(func([]interface{}) []interface{} {
return rets
})
return c
}
// Times declares the exact number of times a function call is expected to be executed.
func (c *Call) Times(n int) *Call {
c.minCalls, c.maxCalls = n, n
return c
}
// SetArg declares an action that will set the nth argument's value,
// indirected through a pointer. Or, in the case of a slice, SetArg
// will copy value's elements into the nth argument.
func (c *Call) SetArg(n int, value interface{}) *Call {
c.t.Helper()
mt := c.methodType
// TODO: This will break on variadic methods.
// We will need to check those at invocation time.
if n < 0 || n >= mt.NumIn() {
c.t.Fatalf("SetArg(%d, ...) called for a method with %d args [%s]",
n, mt.NumIn(), c.origin)
}
// Permit setting argument through an interface.
// In the interface case, we don't (nay, can't) check the type here.
at := mt.In(n)
switch at.Kind() {
case reflect.Ptr:
dt := at.Elem()
if vt := reflect.TypeOf(value); !vt.AssignableTo(dt) {
c.t.Fatalf("SetArg(%d, ...) argument is a %v, not assignable to %v [%s]",
n, vt, dt, c.origin)
}
case reflect.Interface:
// nothing to do
case reflect.Slice:
// nothing to do
default:
c.t.Fatalf("SetArg(%d, ...) referring to argument of non-pointer non-interface non-slice type %v [%s]",
n, at, c.origin)
}
c.addAction(func(args []interface{}) []interface{} {
v := reflect.ValueOf(value)
switch reflect.TypeOf(args[n]).Kind() {
case reflect.Slice:
setSlice(args[n], v)
default:
reflect.ValueOf(args[n]).Elem().Set(v)
}
return nil
})
return c
}
// isPreReq returns true if other is a direct or indirect prerequisite to c.
func (c *Call) isPreReq(other *Call) bool {
for _, preReq := range c.preReqs {
if other == preReq || preReq.isPreReq(other) {
return true
}
}
return false
}
// After declares that the call may only match after preReq has been exhausted.
func (c *Call) After(preReq *Call) *Call {
c.t.Helper()
if c == preReq {
c.t.Fatalf("A call isn't allowed to be its own prerequisite")
}
if preReq.isPreReq(c) {
c.t.Fatalf("Loop in call order: %v is a prerequisite to %v (possibly indirectly).", c, preReq)
}
c.preReqs = append(c.preReqs, preReq)
return c
}
// Returns true if the minimum number of calls have been made.
func (c *Call) satisfied() bool {
return c.numCalls >= c.minCalls
}
// Returns true iff the maximum number of calls have been made.
func (c *Call) exhausted() bool {
return c.numCalls >= c.maxCalls
}
func (c *Call) String() string {
args := make([]string, len(c.args))
for i, arg := range c.args {
args[i] = arg.String()
}
arguments := strings.Join(args, ", ")
return fmt.Sprintf("%T.%v(%s) %s", c.receiver, c.method, arguments, c.origin)
}
// Tests if the given call matches the expected call.
// If yes, returns nil. If no, returns error with message explaining why it does not match.
func (c *Call) matches(args []interface{}) error {
if !c.methodType.IsVariadic() {
if len(args) != len(c.args) {
return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d",
c.origin, len(args), len(c.args))
}
for i, m := range c.args {
if !m.Matches(args[i]) {
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
c.origin, strconv.Itoa(i), args[i], m)
}
}
} else {
if len(c.args) < c.methodType.NumIn()-1 {
return fmt.Errorf("Expected call at %s has the wrong number of matchers. Got: %d, want: %d",
c.origin, len(c.args), c.methodType.NumIn()-1)
}
if len(c.args) != c.methodType.NumIn() && len(args) != len(c.args) {
return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: %d",
c.origin, len(args), len(c.args))
}
if len(args) < len(c.args)-1 {
return fmt.Errorf("Expected call at %s has the wrong number of arguments. Got: %d, want: greater than or equal to %d",
c.origin, len(args), len(c.args)-1)
}
for i, m := range c.args {
if i < c.methodType.NumIn()-1 {
// Non-variadic args
if !m.Matches(args[i]) {
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
c.origin, strconv.Itoa(i), args[i], m)
}
continue
}
// The last arg has a possibility of a variadic argument, so let it branch
// sample: Foo(a int, b int, c ...int)
if i < len(c.args) && i < len(args) {
if m.Matches(args[i]) {
// Got Foo(a, b, c) want Foo(matcherA, matcherB, gomock.Any())
// Got Foo(a, b, c) want Foo(matcherA, matcherB, someSliceMatcher)
// Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC)
// Got Foo(a, b) want Foo(matcherA, matcherB)
// Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD)
continue
}
}
// The number of actual args don't match the number of matchers,
// or the last matcher is a slice and the last arg is not.
// If this function still matches it is because the last matcher
// matches all the remaining arguments or the lack of any.
// Convert the remaining arguments, if any, into a slice of the
// expected type.
vargsType := c.methodType.In(c.methodType.NumIn() - 1)
vargs := reflect.MakeSlice(vargsType, 0, len(args)-i)
for _, arg := range args[i:] {
vargs = reflect.Append(vargs, reflect.ValueOf(arg))
}
if m.Matches(vargs.Interface()) {
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, gomock.Any())
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, someSliceMatcher)
// Got Foo(a, b) want Foo(matcherA, matcherB, gomock.Any())
// Got Foo(a, b) want Foo(matcherA, matcherB, someEmptySliceMatcher)
break
}
// Wrong number of matchers or not match. Fail.
// Got Foo(a, b) want Foo(matcherA, matcherB, matcherC, matcherD)
// Got Foo(a, b, c) want Foo(matcherA, matcherB, matcherC, matcherD)
// Got Foo(a, b, c, d) want Foo(matcherA, matcherB, matcherC, matcherD, matcherE)
// Got Foo(a, b, c, d, e) want Foo(matcherA, matcherB, matcherC, matcherD)
// Got Foo(a, b, c) want Foo(matcherA, matcherB)
return fmt.Errorf("Expected call at %s doesn't match the argument at index %s.\nGot: %v\nWant: %v",
c.origin, strconv.Itoa(i), args[i:], c.args[i])
}
}
// Check that all prerequisite calls have been satisfied.
for _, preReqCall := range c.preReqs {
if !preReqCall.satisfied() {
return fmt.Errorf("Expected call at %s doesn't have a prerequisite call satisfied:\n%v\nshould be called before:\n%v",
c.origin, preReqCall, c)
}
}
// Check that the call is not exhausted.
if c.exhausted() {
return fmt.Errorf("Expected call at %s has already been called the max number of times.", c.origin)
}
return nil
}
// dropPrereqs tells the expected Call to not re-check prerequisite calls any
// longer, and to return its current set.
func (c *Call) dropPrereqs() (preReqs []*Call) {
preReqs = c.preReqs
c.preReqs = nil
return
}
func (c *Call) call(args []interface{}) []func([]interface{}) []interface{} {
c.numCalls++
return c.actions
}
// InOrder declares that the given calls should occur in order.
func InOrder(calls ...*Call) {
for i := 1; i < len(calls); i++ {
calls[i].After(calls[i-1])
}
}
func setSlice(arg interface{}, v reflect.Value) {
va := reflect.ValueOf(arg)
for i := 0; i < v.Len(); i++ {
va.Index(i).Set(v.Index(i))
}
}
func (c *Call) addAction(action func([]interface{}) []interface{}) {
c.actions = append(c.actions, action)
}

51
vendor/github.com/golang/mock/gomock/call_test.go generated vendored Normal file
View File

@@ -0,0 +1,51 @@
package gomock
import (
"testing"
)
type mockTestReporter struct {
errorCalls int
fatalCalls int
}
func (o *mockTestReporter) Errorf(format string, args ...interface{}) {
o.errorCalls++
}
func (o *mockTestReporter) Fatalf(format string, args ...interface{}) {
o.fatalCalls++
}
func (o *mockTestReporter) Helper() {}
func TestCall_After(t *testing.T) {
t.Run("SelfPrereqCallsFatalf", func(t *testing.T) {
tr1 := &mockTestReporter{}
c := &Call{t: tr1}
c.After(c)
if tr1.fatalCalls != 1 {
t.Errorf("number of fatal calls == %v, want 1", tr1.fatalCalls)
}
})
t.Run("LoopInCallOrderCallsFatalf", func(t *testing.T) {
tr1 := &mockTestReporter{}
tr2 := &mockTestReporter{}
c1 := &Call{t: tr1}
c2 := &Call{t: tr2}
c1.After(c2)
c2.After(c1)
if tr1.errorCalls != 0 || tr1.fatalCalls != 0 {
t.Error("unexpected errors")
}
if tr2.fatalCalls != 1 {
t.Errorf("number of fatal calls == %v, want 1", tr2.fatalCalls)
}
})
}

108
vendor/github.com/golang/mock/gomock/callset.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gomock
import (
"bytes"
"fmt"
)
// callSet represents a set of expected calls, indexed by receiver and method
// name.
type callSet struct {
// Calls that are still expected.
expected map[callSetKey][]*Call
// Calls that have been exhausted.
exhausted map[callSetKey][]*Call
}
// callSetKey is the key in the maps in callSet
type callSetKey struct {
receiver interface{}
fname string
}
func newCallSet() *callSet {
return &callSet{make(map[callSetKey][]*Call), make(map[callSetKey][]*Call)}
}
// Add adds a new expected call.
func (cs callSet) Add(call *Call) {
key := callSetKey{call.receiver, call.method}
m := cs.expected
if call.exhausted() {
m = cs.exhausted
}
m[key] = append(m[key], call)
}
// Remove removes an expected call.
func (cs callSet) Remove(call *Call) {
key := callSetKey{call.receiver, call.method}
calls := cs.expected[key]
for i, c := range calls {
if c == call {
// maintain order for remaining calls
cs.expected[key] = append(calls[:i], calls[i+1:]...)
cs.exhausted[key] = append(cs.exhausted[key], call)
break
}
}
}
// FindMatch searches for a matching call. Returns error with explanation message if no call matched.
func (cs callSet) FindMatch(receiver interface{}, method string, args []interface{}) (*Call, error) {
key := callSetKey{receiver, method}
// Search through the expected calls.
expected := cs.expected[key]
var callsErrors bytes.Buffer
for _, call := range expected {
err := call.matches(args)
if err != nil {
fmt.Fprintf(&callsErrors, "\n%v", err)
} else {
return call, nil
}
}
// If we haven't found a match then search through the exhausted calls so we
// get useful error messages.
exhausted := cs.exhausted[key]
for _, call := range exhausted {
if err := call.matches(args); err != nil {
fmt.Fprintf(&callsErrors, "\n%v", err)
}
}
if len(expected)+len(exhausted) == 0 {
fmt.Fprintf(&callsErrors, "there are no expected calls of the method %q for that receiver", method)
}
return nil, fmt.Errorf(callsErrors.String())
}
// Failures returns the calls that are not satisfied.
func (cs callSet) Failures() []*Call {
failures := make([]*Call, 0, len(cs.expected))
for _, calls := range cs.expected {
for _, call := range calls {
if !call.satisfied() {
failures = append(failures, call)
}
}
}
return failures
}

76
vendor/github.com/golang/mock/gomock/callset_test.go generated vendored Normal file
View File

@@ -0,0 +1,76 @@
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gomock
import (
"reflect"
"testing"
)
type receiverType struct{}
func (receiverType) Func() {}
func TestCallSetAdd(t *testing.T) {
method := "TestMethod"
var receiver interface{} = "TestReceiver"
cs := newCallSet()
numCalls := 10
for i := 0; i < numCalls; i++ {
cs.Add(newCall(t, receiver, method, reflect.TypeOf(receiverType{}.Func)))
}
call, err := cs.FindMatch(receiver, method, []interface{}{})
if err != nil {
t.Fatalf("FindMatch: %v", err)
}
if call == nil {
t.Fatalf("FindMatch: Got nil, want non-nil *Call")
}
}
func TestCallSetRemove(t *testing.T) {
method := "TestMethod"
var receiver interface{} = "TestReceiver"
cs := newCallSet()
ourCalls := []*Call{}
numCalls := 10
for i := 0; i < numCalls; i++ {
// NOTE: abuse the `numCalls` value to convey initial ordering of mocked calls
generatedCall := &Call{receiver: receiver, method: method, numCalls: i}
cs.Add(generatedCall)
ourCalls = append(ourCalls, generatedCall)
}
// validateOrder validates that the calls in the array are ordered as they were added
validateOrder := func(calls []*Call) {
// lastNum tracks the last `numCalls` (call order) value seen
lastNum := -1
for _, c := range calls {
if lastNum >= c.numCalls {
t.Errorf("found call %d after call %d", c.numCalls, lastNum)
}
lastNum = c.numCalls
}
}
for _, c := range ourCalls {
validateOrder(cs.expected[callSetKey{receiver, method}])
cs.Remove(c)
}
}

264
vendor/github.com/golang/mock/gomock/controller.go generated vendored Normal file
View File

@@ -0,0 +1,264 @@
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package gomock is a mock framework for Go.
//
// Standard usage:
// (1) Define an interface that you wish to mock.
// type MyInterface interface {
// SomeMethod(x int64, y string)
// }
// (2) Use mockgen to generate a mock from the interface.
// (3) Use the mock in a test:
// func TestMyThing(t *testing.T) {
// mockCtrl := gomock.NewController(t)
// defer mockCtrl.Finish()
//
// mockObj := something.NewMockMyInterface(mockCtrl)
// mockObj.EXPECT().SomeMethod(4, "blah")
// // pass mockObj to a real object and play with it.
// }
//
// By default, expected calls are not enforced to run in any particular order.
// Call order dependency can be enforced by use of InOrder and/or Call.After.
// Call.After can create more varied call order dependencies, but InOrder is
// often more convenient.
//
// The following examples create equivalent call order dependencies.
//
// Example of using Call.After to chain expected call order:
//
// firstCall := mockObj.EXPECT().SomeMethod(1, "first")
// secondCall := mockObj.EXPECT().SomeMethod(2, "second").After(firstCall)
// mockObj.EXPECT().SomeMethod(3, "third").After(secondCall)
//
// Example of using InOrder to declare expected call order:
//
// gomock.InOrder(
// mockObj.EXPECT().SomeMethod(1, "first"),
// mockObj.EXPECT().SomeMethod(2, "second"),
// mockObj.EXPECT().SomeMethod(3, "third"),
// )
//
// TODO:
// - Handle different argument/return types (e.g. ..., chan, map, interface).
package gomock
import (
"context"
"fmt"
"reflect"
"runtime"
"sync"
)
// A TestReporter is something that can be used to report test failures. It
// is satisfied by the standard library's *testing.T.
type TestReporter interface {
Errorf(format string, args ...interface{})
Fatalf(format string, args ...interface{})
}
// TestHelper is a TestReporter that has the Helper method. It is satisfied
// by the standard library's *testing.T.
type TestHelper interface {
TestReporter
Helper()
}
// A Controller represents the top-level control of a mock ecosystem. It
// defines the scope and lifetime of mock objects, as well as their
// expectations. It is safe to call Controller's methods from multiple
// goroutines. Each test should create a new Controller and invoke Finish via
// defer.
//
// func TestFoo(t *testing.T) {
// ctrl := gomock.NewController(st)
// defer ctrl.Finish()
// // ..
// }
//
// func TestBar(t *testing.T) {
// t.Run("Sub-Test-1", st) {
// ctrl := gomock.NewController(st)
// defer ctrl.Finish()
// // ..
// })
// t.Run("Sub-Test-2", st) {
// ctrl := gomock.NewController(st)
// defer ctrl.Finish()
// // ..
// })
// })
type Controller struct {
// T should only be called within a generated mock. It is not intended to
// be used in user code and may be changed in future versions. T is the
// TestReporter passed in when creating the Controller via NewController.
// If the TestReporter does not implment a TestHelper it will be wrapped
// with a nopTestHelper.
T TestHelper
mu sync.Mutex
expectedCalls *callSet
finished bool
}
// NewController returns a new Controller. It is the preferred way to create a
// Controller.
func NewController(t TestReporter) *Controller {
h, ok := t.(TestHelper)
if !ok {
h = nopTestHelper{t}
}
return &Controller{
T: h,
expectedCalls: newCallSet(),
}
}
type cancelReporter struct {
TestHelper
cancel func()
}
func (r *cancelReporter) Errorf(format string, args ...interface{}) {
r.TestHelper.Errorf(format, args...)
}
func (r *cancelReporter) Fatalf(format string, args ...interface{}) {
defer r.cancel()
r.TestHelper.Fatalf(format, args...)
}
// WithContext returns a new Controller and a Context, which is cancelled on any
// fatal failure.
func WithContext(ctx context.Context, t TestReporter) (*Controller, context.Context) {
h, ok := t.(TestHelper)
if !ok {
h = nopTestHelper{t}
}
ctx, cancel := context.WithCancel(ctx)
return NewController(&cancelReporter{h, cancel}), ctx
}
type nopTestHelper struct {
TestReporter
}
func (h nopTestHelper) Helper() {}
// RecordCall is called by a mock. It should not be called by user code.
func (ctrl *Controller) RecordCall(receiver interface{}, method string, args ...interface{}) *Call {
ctrl.T.Helper()
recv := reflect.ValueOf(receiver)
for i := 0; i < recv.Type().NumMethod(); i++ {
if recv.Type().Method(i).Name == method {
return ctrl.RecordCallWithMethodType(receiver, method, recv.Method(i).Type(), args...)
}
}
ctrl.T.Fatalf("gomock: failed finding method %s on %T", method, receiver)
panic("unreachable")
}
// RecordCallWithMethodType is called by a mock. It should not be called by user code.
func (ctrl *Controller) RecordCallWithMethodType(receiver interface{}, method string, methodType reflect.Type, args ...interface{}) *Call {
ctrl.T.Helper()
call := newCall(ctrl.T, receiver, method, methodType, args...)
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
ctrl.expectedCalls.Add(call)
return call
}
// Call is called by a mock. It should not be called by user code.
func (ctrl *Controller) Call(receiver interface{}, method string, args ...interface{}) []interface{} {
ctrl.T.Helper()
// Nest this code so we can use defer to make sure the lock is released.
actions := func() []func([]interface{}) []interface{} {
ctrl.T.Helper()
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
expected, err := ctrl.expectedCalls.FindMatch(receiver, method, args)
if err != nil {
origin := callerInfo(2)
ctrl.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", receiver, method, args, origin, err)
}
// Two things happen here:
// * the matching call no longer needs to check prerequite calls,
// * and the prerequite calls are no longer expected, so remove them.
preReqCalls := expected.dropPrereqs()
for _, preReqCall := range preReqCalls {
ctrl.expectedCalls.Remove(preReqCall)
}
actions := expected.call(args)
if expected.exhausted() {
ctrl.expectedCalls.Remove(expected)
}
return actions
}()
var rets []interface{}
for _, action := range actions {
if r := action(args); r != nil {
rets = r
}
}
return rets
}
// Finish checks to see if all the methods that were expected to be called
// were called. It should be invoked for each Controller. It is not idempotent
// and therefore can only be invoked once.
func (ctrl *Controller) Finish() {
ctrl.T.Helper()
ctrl.mu.Lock()
defer ctrl.mu.Unlock()
if ctrl.finished {
ctrl.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.")
}
ctrl.finished = true
// If we're currently panicking, probably because this is a deferred call,
// pass through the panic.
if err := recover(); err != nil {
panic(err)
}
// Check that all remaining expected calls are satisfied.
failures := ctrl.expectedCalls.Failures()
for _, call := range failures {
ctrl.T.Errorf("missing call(s) to %v", call)
}
if len(failures) != 0 {
ctrl.T.Fatalf("aborting test due to missing call(s)")
}
}
func callerInfo(skip int) string {
if _, file, line, ok := runtime.Caller(skip + 1); ok {
return fmt.Sprintf("%s:%d", file, line)
}
return "unknown file"
}

739
vendor/github.com/golang/mock/gomock/controller_test.go generated vendored Normal file
View File

@@ -0,0 +1,739 @@
// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gomock_test
import (
"fmt"
"reflect"
"testing"
"strings"
"github.com/golang/mock/gomock"
)
type ErrorReporter struct {
t *testing.T
log []string
failed bool
fatalToken struct{}
}
func NewErrorReporter(t *testing.T) *ErrorReporter {
return &ErrorReporter{t: t}
}
func (e *ErrorReporter) reportLog() {
for _, entry := range e.log {
e.t.Log(entry)
}
}
func (e *ErrorReporter) assertPass(msg string) {
if e.failed {
e.t.Errorf("Expected pass, but got failure(s): %s", msg)
e.reportLog()
}
}
func (e *ErrorReporter) assertFail(msg string) {
if !e.failed {
e.t.Errorf("Expected failure, but got pass: %s", msg)
}
}
// Use to check that code triggers a fatal test failure.
func (e *ErrorReporter) assertFatal(fn func(), expectedErrMsgs ...string) {
defer func() {
err := recover()
if err == nil {
var actual string
if e.failed {
actual = "non-fatal failure"
} else {
actual = "pass"
}
e.t.Error("Expected fatal failure, but got a", actual)
} else if token, ok := err.(*struct{}); ok && token == &e.fatalToken {
// This is okay - the panic is from Fatalf().
if expectedErrMsgs != nil {
// assert that the actual error message
// contains expectedErrMsgs
// check the last actualErrMsg, because the previous messages come from previous errors
actualErrMsg := e.log[len(e.log)-1]
for _, expectedErrMsg := range expectedErrMsgs {
if !strings.Contains(actualErrMsg, expectedErrMsg) {
e.t.Errorf("Error message:\ngot: %q\nwant to contain: %q\n", actualErrMsg, expectedErrMsg)
}
}
}
return
} else {
// Some other panic.
panic(err)
}
}()
fn()
}
// recoverUnexpectedFatal can be used as a deferred call in test cases to
// recover from and display a call to ErrorReporter.Fatalf().
func (e *ErrorReporter) recoverUnexpectedFatal() {
err := recover()
if err == nil {
// No panic.
} else if token, ok := err.(*struct{}); ok && token == &e.fatalToken {
// Unexpected fatal error happened.
e.t.Error("Got unexpected fatal error(s). All errors up to this point:")
e.reportLog()
return
} else {
// Some other panic.
panic(err)
}
}
func (e *ErrorReporter) Logf(format string, args ...interface{}) {
e.log = append(e.log, fmt.Sprintf(format, args...))
}
func (e *ErrorReporter) Errorf(format string, args ...interface{}) {
e.Logf(format, args...)
e.failed = true
}
func (e *ErrorReporter) Fatalf(format string, args ...interface{}) {
e.Logf(format, args...)
e.failed = true
panic(&e.fatalToken)
}
type HelperReporter struct {
gomock.TestReporter
helper int
}
func (h *HelperReporter) Helper() {
h.helper++
}
// A type purely for use as a receiver in testing the Controller.
type Subject struct{}
func (s *Subject) FooMethod(arg string) int {
return 0
}
func (s *Subject) BarMethod(arg string) int {
return 0
}
func (s *Subject) VariadicMethod(arg int, vararg ...string) {}
// A type purely for ActOnTestStructMethod
type TestStruct struct {
Number int
Message string
}
func (s *Subject) ActOnTestStructMethod(arg TestStruct, arg1 int) int {
return 0
}
func (s *Subject) SetArgMethod(sliceArg []byte, ptrArg *int) {}
func assertEqual(t *testing.T, expected interface{}, actual interface{}) {
if !reflect.DeepEqual(expected, actual) {
t.Errorf("Expected %+v, but got %+v", expected, actual)
}
}
func createFixtures(t *testing.T) (reporter *ErrorReporter, ctrl *gomock.Controller) {
// reporter acts as a testing.T-like object that we pass to the
// Controller. We use it to test that the mock considered tests
// successful or failed.
reporter = NewErrorReporter(t)
ctrl = gomock.NewController(reporter)
return
}
func TestNoCalls(t *testing.T) {
reporter, ctrl := createFixtures(t)
ctrl.Finish()
reporter.assertPass("No calls expected or made.")
}
func TestNoRecordedCallsForAReceiver(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
reporter.assertFatal(func() {
ctrl.Call(subject, "NotRecordedMethod", "argument")
}, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver")
ctrl.Finish()
}
func TestNoRecordedMatchingMethodNameForAReceiver(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument")
reporter.assertFatal(func() {
ctrl.Call(subject, "NotRecordedMethod", "argument")
}, "Unexpected call to", "there are no expected calls of the method \"NotRecordedMethod\" for that receiver")
reporter.assertFatal(func() {
// The expected call wasn't made.
ctrl.Finish()
})
}
// This tests that a call with an arguments of some primitive type matches a recorded call.
func TestExpectedMethodCall(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Finish()
reporter.assertPass("Expected method call made.")
}
func TestUnexpectedMethodCall(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
reporter.assertFatal(func() {
ctrl.Call(subject, "FooMethod", "argument")
})
ctrl.Finish()
}
func TestRepeatedCall(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").Times(3)
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
reporter.assertPass("After expected repeated method calls.")
reporter.assertFatal(func() {
ctrl.Call(subject, "FooMethod", "argument")
})
ctrl.Finish()
reporter.assertFail("After calling one too many times.")
}
func TestUnexpectedArgCount(t *testing.T) {
reporter, ctrl := createFixtures(t)
defer reporter.recoverUnexpectedFatal()
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument")
reporter.assertFatal(func() {
// This call is made with the wrong number of arguments...
ctrl.Call(subject, "FooMethod", "argument", "extra_argument")
}, "Unexpected call to", "wrong number of arguments", "Got: 2, want: 1")
reporter.assertFatal(func() {
// ... so is this.
ctrl.Call(subject, "FooMethod")
}, "Unexpected call to", "wrong number of arguments", "Got: 0, want: 1")
reporter.assertFatal(func() {
// The expected call wasn't made.
ctrl.Finish()
})
}
// This tests that a call with complex arguments (a struct and some primitive type) matches a recorded call.
func TestExpectedMethodCall_CustomStruct(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
expectedArg0 := TestStruct{Number: 123, Message: "hello"}
ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15)
ctrl.Call(subject, "ActOnTestStructMethod", expectedArg0, 15)
reporter.assertPass("Expected method call made.")
}
func TestUnexpectedArgValue_FirstArg(t *testing.T) {
reporter, ctrl := createFixtures(t)
defer reporter.recoverUnexpectedFatal()
subject := new(Subject)
expectedArg0 := TestStruct{Number: 123, Message: "hello"}
ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15)
reporter.assertFatal(func() {
// the method argument (of TestStruct type) has 1 unexpected value (for the Message field)
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "no message"}, 15)
}, "Unexpected call to", "doesn't match the argument at index 0",
"Got: {123 no message}\nWant: is equal to {123 hello}")
reporter.assertFatal(func() {
// the method argument (of TestStruct type) has 2 unexpected values (for both fields)
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 11, Message: "no message"}, 15)
}, "Unexpected call to", "doesn't match the argument at index 0",
"Got: {11 no message}\nWant: is equal to {123 hello}")
reporter.assertFatal(func() {
// The expected call wasn't made.
ctrl.Finish()
})
}
func TestUnexpectedArgValue_SecondtArg(t *testing.T) {
reporter, ctrl := createFixtures(t)
defer reporter.recoverUnexpectedFatal()
subject := new(Subject)
expectedArg0 := TestStruct{Number: 123, Message: "hello"}
ctrl.RecordCall(subject, "ActOnTestStructMethod", expectedArg0, 15)
reporter.assertFatal(func() {
ctrl.Call(subject, "ActOnTestStructMethod", TestStruct{Number: 123, Message: "hello"}, 3)
}, "Unexpected call to", "doesn't match the argument at index 1",
"Got: 3\nWant: is equal to 15")
reporter.assertFatal(func() {
// The expected call wasn't made.
ctrl.Finish()
})
}
func TestAnyTimes(t *testing.T) {
reporter, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").AnyTimes()
for i := 0; i < 100; i++ {
ctrl.Call(subject, "FooMethod", "argument")
}
reporter.assertPass("After 100 method calls.")
ctrl.Finish()
}
func TestMinTimes1(t *testing.T) {
// It fails if there are no calls
reporter, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
reporter.assertFatal(func() {
ctrl.Finish()
})
// It succeeds if there is one call
reporter, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Finish()
// It succeeds if there are many calls
reporter, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(1)
for i := 0; i < 100; i++ {
ctrl.Call(subject, "FooMethod", "argument")
}
ctrl.Finish()
}
func TestMaxTimes1(t *testing.T) {
// It succeeds if there are no calls
_, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1)
ctrl.Finish()
// It succeeds if there is one call
_, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1)
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Finish()
//It fails if there are more
reporter, ctrl := createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(1)
ctrl.Call(subject, "FooMethod", "argument")
reporter.assertFatal(func() {
ctrl.Call(subject, "FooMethod", "argument")
})
ctrl.Finish()
}
func TestMinMaxTimes(t *testing.T) {
// It fails if there are less calls than specified
reporter, ctrl := createFixtures(t)
subject := new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2)
ctrl.Call(subject, "FooMethod", "argument")
reporter.assertFatal(func() {
ctrl.Finish()
})
// It fails if there are more calls than specified
reporter, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MinTimes(2).MaxTimes(2)
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
reporter.assertFatal(func() {
ctrl.Call(subject, "FooMethod", "argument")
})
// It succeeds if there is just the right number of calls
reporter, ctrl = createFixtures(t)
subject = new(Subject)
ctrl.RecordCall(subject, "FooMethod", "argument").MaxTimes(2).MinTimes(2)
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Call(subject, "FooMethod", "argument")
ctrl.Finish()
}
func TestDo(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
doCalled := false
var argument string
ctrl.RecordCall(subject, "FooMethod", "argument").Do(
func(arg string) {
doCalled = true
argument = arg
})
if doCalled {
t.Error("Do() callback called too early.")
}
ctrl.Call(subject, "FooMethod", "argument")
if !doCalled {
t.Error("Do() callback not called.")
}
if "argument" != argument {
t.Error("Do callback received wrong argument.")
}
ctrl.Finish()
}
func TestDoAndReturn(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
doCalled := false
var argument string
ctrl.RecordCall(subject, "FooMethod", "argument").DoAndReturn(
func(arg string) int {
doCalled = true
argument = arg
return 5
})
if doCalled {
t.Error("Do() callback called too early.")
}
rets := ctrl.Call(subject, "FooMethod", "argument")
if !doCalled {
t.Error("Do() callback not called.")
}
if "argument" != argument {
t.Error("Do callback received wrong argument.")
}
if len(rets) != 1 {
t.Fatalf("Return values from Call: got %d, want 1", len(rets))
}
if ret, ok := rets[0].(int); !ok {
t.Fatalf("Return value is not an int")
} else if ret != 5 {
t.Errorf("DoAndReturn return value: got %d, want 5", ret)
}
ctrl.Finish()
}
func TestSetArgSlice(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
var in = []byte{4, 5, 6}
var set = []byte{1, 2, 3}
ctrl.RecordCall(subject, "SetArgMethod", in, nil).SetArg(0, set)
ctrl.Call(subject, "SetArgMethod", in, nil)
if !reflect.DeepEqual(in, set) {
t.Error("Expected SetArg() to modify input slice argument")
}
ctrl.Finish()
}
func TestSetArgPtr(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
var in int = 43
const set = 42
ctrl.RecordCall(subject, "SetArgMethod", nil, &in).SetArg(1, set)
ctrl.Call(subject, "SetArgMethod", nil, &in)
if in != set {
t.Error("Expected SetArg() to modify value pointed to by argument")
}
ctrl.Finish()
}
func TestReturn(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
// Unspecified return should produce "zero" result.
ctrl.RecordCall(subject, "FooMethod", "zero")
ctrl.RecordCall(subject, "FooMethod", "five").Return(5)
assertEqual(
t,
[]interface{}{0},
ctrl.Call(subject, "FooMethod", "zero"))
assertEqual(
t,
[]interface{}{5},
ctrl.Call(subject, "FooMethod", "five"))
ctrl.Finish()
}
func TestUnorderedCalls(t *testing.T) {
reporter, ctrl := createFixtures(t)
defer reporter.recoverUnexpectedFatal()
subjectTwo := new(Subject)
subjectOne := new(Subject)
ctrl.RecordCall(subjectOne, "FooMethod", "1")
ctrl.RecordCall(subjectOne, "BarMethod", "2")
ctrl.RecordCall(subjectTwo, "FooMethod", "3")
ctrl.RecordCall(subjectTwo, "BarMethod", "4")
// Make the calls in a different order, which should be fine.
ctrl.Call(subjectOne, "BarMethod", "2")
ctrl.Call(subjectTwo, "FooMethod", "3")
ctrl.Call(subjectTwo, "BarMethod", "4")
ctrl.Call(subjectOne, "FooMethod", "1")
reporter.assertPass("After making all calls in different order")
ctrl.Finish()
reporter.assertPass("After finish")
}
func commonTestOrderedCalls(t *testing.T) (reporter *ErrorReporter, ctrl *gomock.Controller, subjectOne, subjectTwo *Subject) {
reporter, ctrl = createFixtures(t)
subjectOne = new(Subject)
subjectTwo = new(Subject)
gomock.InOrder(
ctrl.RecordCall(subjectOne, "FooMethod", "1").AnyTimes(),
ctrl.RecordCall(subjectTwo, "FooMethod", "2"),
ctrl.RecordCall(subjectTwo, "BarMethod", "3"),
)
return
}
func TestOrderedCallsCorrect(t *testing.T) {
reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t)
ctrl.Call(subjectOne, "FooMethod", "1")
ctrl.Call(subjectTwo, "FooMethod", "2")
ctrl.Call(subjectTwo, "BarMethod", "3")
ctrl.Finish()
reporter.assertPass("After finish")
}
func TestOrderedCallsInCorrect(t *testing.T) {
reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t)
ctrl.Call(subjectOne, "FooMethod", "1")
reporter.assertFatal(func() {
// FooMethod(2) should be called before BarMethod(3)
ctrl.Call(subjectTwo, "BarMethod", "3")
}, "Unexpected call to", "Subject.BarMethod([3])", "doesn't have a prerequisite call satisfied")
}
// Test that calls that are prerequisites to other calls but have maxCalls >
// minCalls are removed from the expected call set.
func TestOrderedCallsWithPreReqMaxUnbounded(t *testing.T) {
reporter, ctrl, subjectOne, subjectTwo := commonTestOrderedCalls(t)
// Initially we should be able to call FooMethod("1") as many times as we
// want.
ctrl.Call(subjectOne, "FooMethod", "1")
ctrl.Call(subjectOne, "FooMethod", "1")
// But calling something that has it as a prerequite should remove it from
// the expected call set. This allows tests to ensure that FooMethod("1") is
// *not* called after FooMethod("2").
ctrl.Call(subjectTwo, "FooMethod", "2")
// Therefore this call should fail:
reporter.assertFatal(func() {
ctrl.Call(subjectOne, "FooMethod", "1")
})
}
func TestCallAfterLoopPanic(t *testing.T) {
_, ctrl := createFixtures(t)
subject := new(Subject)
firstCall := ctrl.RecordCall(subject, "FooMethod", "1")
secondCall := ctrl.RecordCall(subject, "FooMethod", "2")
thirdCall := ctrl.RecordCall(subject, "FooMethod", "3")
gomock.InOrder(firstCall, secondCall, thirdCall)
defer func() {
err := recover()
if err == nil {
t.Error("Call.After creation of dependency loop did not panic.")
}
}()
// This should panic due to dependency loop.
firstCall.After(thirdCall)
}
func TestPanicOverridesExpectationChecks(t *testing.T) {
ctrl := gomock.NewController(t)
reporter := NewErrorReporter(t)
reporter.assertFatal(func() {
ctrl.RecordCall(new(Subject), "FooMethod", "1")
defer ctrl.Finish()
reporter.Fatalf("Intentional panic")
})
}
func TestSetArgWithBadType(t *testing.T) {
rep, ctrl := createFixtures(t)
defer ctrl.Finish()
s := new(Subject)
// This should catch a type error:
rep.assertFatal(func() {
ctrl.RecordCall(s, "FooMethod", "1").SetArg(0, "blah")
})
ctrl.Call(s, "FooMethod", "1")
}
func TestTimes0(t *testing.T) {
rep, ctrl := createFixtures(t)
defer ctrl.Finish()
s := new(Subject)
ctrl.RecordCall(s, "FooMethod", "arg").Times(0)
rep.assertFatal(func() {
ctrl.Call(s, "FooMethod", "arg")
})
}
func TestVariadicMatching(t *testing.T) {
rep, ctrl := createFixtures(t)
defer rep.recoverUnexpectedFatal()
s := new(Subject)
ctrl.RecordCall(s, "VariadicMethod", 0, "1", "2")
ctrl.Call(s, "VariadicMethod", 0, "1", "2")
ctrl.Finish()
rep.assertPass("variadic matching works")
}
func TestVariadicNoMatch(t *testing.T) {
rep, ctrl := createFixtures(t)
defer rep.recoverUnexpectedFatal()
s := new(Subject)
ctrl.RecordCall(s, "VariadicMethod", 0)
rep.assertFatal(func() {
ctrl.Call(s, "VariadicMethod", 1)
}, "Expected call at", "doesn't match the argument at index 0",
"Got: 1\nWant: is equal to 0")
ctrl.Call(s, "VariadicMethod", 0)
ctrl.Finish()
}
func TestVariadicMatchingWithSlice(t *testing.T) {
testCases := [][]string{
{"1"},
{"1", "2"},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("%d arguments", len(tc)), func(t *testing.T) {
rep, ctrl := createFixtures(t)
defer rep.recoverUnexpectedFatal()
s := new(Subject)
ctrl.RecordCall(s, "VariadicMethod", 1, tc)
args := make([]interface{}, len(tc)+1)
args[0] = 1
for i, arg := range tc {
args[i+1] = arg
}
ctrl.Call(s, "VariadicMethod", args...)
ctrl.Finish()
rep.assertPass("slices can be used as matchers for variadic arguments")
})
}
}
func TestDuplicateFinishCallFails(t *testing.T) {
rep, ctrl := createFixtures(t)
ctrl.Finish()
rep.assertPass("the first Finish call should succeed")
rep.assertFatal(ctrl.Finish, "Controller.Finish was called more than once. It has to be called exactly once.")
}
func TestNoHelper(t *testing.T) {
ctrlNoHelper := gomock.NewController(NewErrorReporter(t))
// doesn't panic
ctrlNoHelper.T.Helper()
}
func TestWithHelper(t *testing.T) {
withHelper := &HelperReporter{TestReporter: NewErrorReporter(t)}
ctrlWithHelper := gomock.NewController(withHelper)
ctrlWithHelper.T.Helper()
if withHelper.helper == 0 {
t.Fatal("expected Helper to be invoked")
}
}

View File

@@ -0,0 +1,61 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/golang/mock/gomock (interfaces: Matcher)
// Package mock_gomock is a generated GoMock package.
package mock_gomock
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockMatcher is a mock of Matcher interface
type MockMatcher struct {
ctrl *gomock.Controller
recorder *MockMatcherMockRecorder
}
// MockMatcherMockRecorder is the mock recorder for MockMatcher
type MockMatcherMockRecorder struct {
mock *MockMatcher
}
// NewMockMatcher creates a new mock instance
func NewMockMatcher(ctrl *gomock.Controller) *MockMatcher {
mock := &MockMatcher{ctrl: ctrl}
mock.recorder = &MockMatcherMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockMatcher) EXPECT() *MockMatcherMockRecorder {
return m.recorder
}
// Matches mocks base method
func (m *MockMatcher) Matches(arg0 interface{}) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Matches", arg0)
ret0, _ := ret[0].(bool)
return ret0
}
// Matches indicates an expected call of Matches
func (mr *MockMatcherMockRecorder) Matches(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Matches", reflect.TypeOf((*MockMatcher)(nil).Matches), arg0)
}
// String mocks base method
func (m *MockMatcher) String() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "String")
ret0, _ := ret[0].(string)
return ret0
}
// String indicates an expected call of String
func (mr *MockMatcherMockRecorder) String() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockMatcher)(nil).String))
}

141
vendor/github.com/golang/mock/gomock/matchers.go generated vendored Normal file
View File

@@ -0,0 +1,141 @@
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gomock
import (
"fmt"
"reflect"
)
// A Matcher is a representation of a class of values.
// It is used to represent the valid or expected arguments to a mocked method.
type Matcher interface {
// Matches returns whether x is a match.
Matches(x interface{}) bool
// String describes what the matcher matches.
String() string
}
type anyMatcher struct{}
func (anyMatcher) Matches(x interface{}) bool {
return true
}
func (anyMatcher) String() string {
return "is anything"
}
type eqMatcher struct {
x interface{}
}
func (e eqMatcher) Matches(x interface{}) bool {
return reflect.DeepEqual(e.x, x)
}
func (e eqMatcher) String() string {
return fmt.Sprintf("is equal to %v", e.x)
}
type nilMatcher struct{}
func (nilMatcher) Matches(x interface{}) bool {
if x == nil {
return true
}
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map,
reflect.Ptr, reflect.Slice:
return v.IsNil()
}
return false
}
func (nilMatcher) String() string {
return "is nil"
}
type notMatcher struct {
m Matcher
}
func (n notMatcher) Matches(x interface{}) bool {
return !n.m.Matches(x)
}
func (n notMatcher) String() string {
// TODO: Improve this if we add a NotString method to the Matcher interface.
return "not(" + n.m.String() + ")"
}
type assignableToTypeOfMatcher struct {
targetType reflect.Type
}
func (m assignableToTypeOfMatcher) Matches(x interface{}) bool {
return reflect.TypeOf(x).AssignableTo(m.targetType)
}
func (m assignableToTypeOfMatcher) String() string {
return "is assignable to " + m.targetType.Name()
}
// Constructors
// Any returns a matcher that always matches.
func Any() Matcher { return anyMatcher{} }
// Eq returns a matcher that matches on equality.
//
// Example usage:
// Eq(5).Matches(5) // returns true
// Eq(5).Matches(4) // returns false
func Eq(x interface{}) Matcher { return eqMatcher{x} }
// Nil returns a matcher that matches if the received value is nil.
//
// Example usage:
// var x *bytes.Buffer
// Nil().Matches(x) // returns true
// x = &bytes.Buffer{}
// Nil().Matches(x) // returns false
func Nil() Matcher { return nilMatcher{} }
// Not reverses the results of its given child matcher.
//
// Example usage:
// Not(Eq(5)).Matches(4) // returns true
// Not(Eq(5)).Matches(5) // returns false
func Not(x interface{}) Matcher {
if m, ok := x.(Matcher); ok {
return notMatcher{m}
}
return notMatcher{Eq(x)}
}
// AssignableToTypeOf is a Matcher that matches if the parameter to the mock
// function is assignable to the type of the parameter to this function.
//
// Example usage:
// var s fmt.Stringer = &bytes.Buffer{}
// AssignableToTypeOf(s).Matches(time.Second) // returns true
// AssignableToTypeOf(s).Matches(99) // returns false
func AssignableToTypeOf(x interface{}) Matcher {
return assignableToTypeOfMatcher{reflect.TypeOf(x)}
}

119
vendor/github.com/golang/mock/gomock/matchers_test.go generated vendored Normal file
View File

@@ -0,0 +1,119 @@
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//go:generate mockgen -destination internal/mock_matcher/mock_matcher.go github.com/golang/mock/gomock Matcher
package gomock_test
import (
"errors"
"testing"
"github.com/golang/mock/gomock"
mock_matcher "github.com/golang/mock/gomock/internal/mock_matcher"
)
func TestMatchers(t *testing.T) {
type e interface{}
type testCase struct {
matcher gomock.Matcher
yes, no []e
}
tests := []testCase{
{gomock.Any(), []e{3, nil, "foo"}, nil},
{gomock.Eq(4), []e{4}, []e{3, "blah", nil, int64(4)}},
{gomock.Nil(),
[]e{nil, (error)(nil), (chan bool)(nil), (*int)(nil)},
[]e{"", 0, make(chan bool), errors.New("err"), new(int)}},
{gomock.Not(gomock.Eq(4)), []e{3, "blah", nil, int64(4)}, []e{4}},
}
for i, test := range tests {
for _, x := range test.yes {
if !test.matcher.Matches(x) {
t.Errorf(`test %d: "%v %s" should be true.`, i, x, test.matcher)
}
}
for _, x := range test.no {
if test.matcher.Matches(x) {
t.Errorf(`test %d: "%v %s" should be false.`, i, x, test.matcher)
}
}
}
}
// A more thorough test of notMatcher
func TestNotMatcher(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockMatcher := mock_matcher.NewMockMatcher(ctrl)
notMatcher := gomock.Not(mockMatcher)
mockMatcher.EXPECT().Matches(4).Return(true)
if match := notMatcher.Matches(4); match {
t.Errorf("notMatcher should not match 4")
}
mockMatcher.EXPECT().Matches(5).Return(false)
if match := notMatcher.Matches(5); !match {
t.Errorf("notMatcher should match 5")
}
}
type Dog struct {
Breed, Name string
}
// A thorough test of assignableToTypeOfMatcher
func TestAssignableToTypeOfMatcher(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
aStr := "def"
anotherStr := "ghi"
if match := gomock.AssignableToTypeOf("abc").Matches(4); match {
t.Errorf(`AssignableToTypeOf("abc") should not match 4`)
}
if match := gomock.AssignableToTypeOf("abc").Matches(&aStr); match {
t.Errorf(`AssignableToTypeOf("abc") should not match &aStr (*string)`)
}
if match := gomock.AssignableToTypeOf("abc").Matches("def"); !match {
t.Errorf(`AssignableToTypeOf("abc") should match "def"`)
}
if match := gomock.AssignableToTypeOf(&aStr).Matches("abc"); match {
t.Errorf(`AssignableToTypeOf(&aStr) should not match "abc"`)
}
if match := gomock.AssignableToTypeOf(&aStr).Matches(&anotherStr); !match {
t.Errorf(`AssignableToTypeOf(&aStr) should match &anotherStr`)
}
if match := gomock.AssignableToTypeOf(0).Matches(4); !match {
t.Errorf(`AssignableToTypeOf(0) should match 4`)
}
if match := gomock.AssignableToTypeOf(0).Matches("def"); match {
t.Errorf(`AssignableToTypeOf(0) should not match "def"`)
}
if match := gomock.AssignableToTypeOf(Dog{}).Matches(&Dog{}); match {
t.Errorf(`AssignableToTypeOf(Dog{}) should not match &Dog{}`)
}
if match := gomock.AssignableToTypeOf(Dog{}).Matches(Dog{Breed: "pug", Name: "Fido"}); !match {
t.Errorf(`AssignableToTypeOf(Dog{}) should match Dog{Breed: "pug", Name: "Fido"}`)
}
if match := gomock.AssignableToTypeOf(&Dog{}).Matches(Dog{}); match {
t.Errorf(`AssignableToTypeOf(&Dog{}) should not match Dog{}`)
}
if match := gomock.AssignableToTypeOf(&Dog{}).Matches(&Dog{Breed: "pug", Name: "Fido"}); !match {
t.Errorf(`AssignableToTypeOf(&Dog{}) should match &Dog{Breed: "pug", Name: "Fido"}`)
}
}

View File

@@ -0,0 +1,36 @@
Embedded interfaces in `aux_files` generate `unknown embedded interface XXX` errors.
See below for example of the problem:
```
// source
import (
alias "some.org/package/imported"
)
type Source interface {
alias.Foreign
}
```
```
// some.org/package/imported
type Foreign interface {
Embedded
}
type Embedded interface {}
```
Attempting to generate a mock will result in an `unknown embedded interface Embedded`.
The issue is that the `fileParser` stores `auxInterfaces` underneath the package name
explicitly specified in the `aux_files` flag.
In the `parseInterface` method, there is an incorrect assumption about an embedded interface
always being in the source file.
```
case *ast.Ident:
// Embedded interface in this package.
ei := p.auxInterfaces[""][v.String()]
if ei == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s", v.String())
}
```

View File

@@ -0,0 +1,18 @@
//go:generate mockgen -aux_files faux=faux/faux.go -destination bugreport_mock.go -package bugreport -source=bugreport.go Example
package bugreport
import (
"log"
"github.com/golang/mock/mockgen/internal/tests/aux_imports_embedded_interface/faux"
)
// Source is an interface w/ an embedded foreign interface
type Source interface {
faux.Foreign
}
func CallForeignMethod(s Source) {
log.Println(s.Method())
}

View File

@@ -0,0 +1,48 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: bugreport.go
// Package bugreport is a generated GoMock package.
package bugreport
import (
gomock "github.com/golang/mock/gomock"
faux "github.com/golang/mock/mockgen/internal/tests/aux_imports_embedded_interface/faux"
reflect "reflect"
)
// MockSource is a mock of Source interface
type MockSource struct {
ctrl *gomock.Controller
recorder *MockSourceMockRecorder
}
// MockSourceMockRecorder is the mock recorder for MockSource
type MockSourceMockRecorder struct {
mock *MockSource
}
// NewMockSource creates a new mock instance
func NewMockSource(ctrl *gomock.Controller) *MockSource {
mock := &MockSource{ctrl: ctrl}
mock.recorder = &MockSourceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockSource) EXPECT() *MockSourceMockRecorder {
return m.recorder
}
// Method mocks base method
func (m *MockSource) Method() faux.Return {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Method")
ret0, _ := ret[0].(faux.Return)
return ret0
}
// Method indicates an expected call of Method
func (mr *MockSourceMockRecorder) Method() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Method", reflect.TypeOf((*MockSource)(nil).Method))
}

View File

@@ -0,0 +1,18 @@
package bugreport
import (
"testing"
"github.com/golang/mock/gomock"
)
// TestValidInterface assesses whether or not the generated mock is valid
func TestValidInterface(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
s := NewMockSource(ctrl)
s.EXPECT().Method().Return("")
CallForeignMethod(s)
}

View File

@@ -0,0 +1,10 @@
package faux
type Foreign interface {
Method() Return
Embedded
}
type Embedded interface{}
type Return interface{}

View File

@@ -0,0 +1,22 @@
# Tests for custom package names
This directory contains test for mockgen generating mocks when imported package
name does not match import path suffix. For example, package with name "client"
is located under import path "github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1".
Prior to this patch:
$ go generate greeter/greeter.go
2018/03/05 22:44:52 Loading input failed: greeter.go:17:11: failed parsing returns: greeter.go:17:14: unknown package "client"
greeter/greeter.go:1: running "mockgen": exit status 1
This can be fixed by manually providing `-imports` flag, like `-imports client=github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1`.
But, mockgen should be able to automatically resolve package names in such situations.
With this patch applied:
$ go generate greeter/greeter.go
$ echo $?
0
Mockgen runs successfully, produced output is equal to [greeter_mock_test.go](greeter/greeter_mock_test.go) content.

View File

@@ -0,0 +1,13 @@
package client
import "fmt"
type Client struct{}
func (c *Client) Greet(in GreetInput) string {
return fmt.Sprintf("Hello, %s!", in.Name)
}
type GreetInput struct {
Name string
}

View File

@@ -0,0 +1,31 @@
//go:generate mockgen -source greeter.go -destination greeter_mock_test.go -package greeter
package greeter
import (
// stdlib import
"fmt"
// non-matching import suffix and package name
"github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1"
// matching import suffix and package name
"github.com/golang/mock/mockgen/internal/tests/custom_package_name/validator"
)
type InputMaker interface {
MakeInput() client.GreetInput
}
type Greeter struct {
InputMaker InputMaker
Client *client.Client
}
func (g *Greeter) Greet() (string, error) {
in := g.InputMaker.MakeInput()
if err := validator.Validate(in.Name); err != nil {
return "", fmt.Errorf("validation failed: %v", err)
}
return g.Client.Greet(in), nil
}

View File

@@ -0,0 +1,48 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: greeter.go
// Package greeter is a generated GoMock package.
package greeter
import (
gomock "github.com/golang/mock/gomock"
v1 "github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1"
reflect "reflect"
)
// MockInputMaker is a mock of InputMaker interface
type MockInputMaker struct {
ctrl *gomock.Controller
recorder *MockInputMakerMockRecorder
}
// MockInputMakerMockRecorder is the mock recorder for MockInputMaker
type MockInputMakerMockRecorder struct {
mock *MockInputMaker
}
// NewMockInputMaker creates a new mock instance
func NewMockInputMaker(ctrl *gomock.Controller) *MockInputMaker {
mock := &MockInputMaker{ctrl: ctrl}
mock.recorder = &MockInputMakerMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInputMaker) EXPECT() *MockInputMakerMockRecorder {
return m.recorder
}
// MakeInput mocks base method
func (m *MockInputMaker) MakeInput() v1.GreetInput {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "MakeInput")
ret0, _ := ret[0].(v1.GreetInput)
return ret0
}
// MakeInput indicates an expected call of MakeInput
func (mr *MockInputMakerMockRecorder) MakeInput() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MakeInput", reflect.TypeOf((*MockInputMaker)(nil).MakeInput))
}

View File

@@ -0,0 +1,37 @@
package greeter
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1"
)
func TestGreeter_Greet(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
input := client.GreetInput{
Name: "Foo",
}
inputMaker := NewMockInputMaker(ctrl)
inputMaker.EXPECT().
MakeInput().
Return(input)
g := &Greeter{
InputMaker: inputMaker,
Client: &client.Client{},
}
greeting, err := g.Greet()
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
expected := "Hello, Foo!"
if greeting != expected {
t.Fatalf("Expected greeting to be %v but got %v", expected, greeting)
}
}

View File

@@ -0,0 +1,5 @@
package validator
func Validate(s string) error {
return nil
}

View File

@@ -0,0 +1,14 @@
//go:generate mockgen -package dot_imports -destination mock.go -source input.go
package dot_imports
import (
"bytes"
. "context"
. "net/http"
)
type WithDotImports interface {
Method1() Request
Method2() *bytes.Buffer
Method3() Context
}

View File

@@ -0,0 +1,78 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: input.go
// Package dot_imports is a generated GoMock package.
package dot_imports
import (
bytes "bytes"
. "context"
gomock "github.com/golang/mock/gomock"
. "net/http"
reflect "reflect"
)
// MockWithDotImports is a mock of WithDotImports interface
type MockWithDotImports struct {
ctrl *gomock.Controller
recorder *MockWithDotImportsMockRecorder
}
// MockWithDotImportsMockRecorder is the mock recorder for MockWithDotImports
type MockWithDotImportsMockRecorder struct {
mock *MockWithDotImports
}
// NewMockWithDotImports creates a new mock instance
func NewMockWithDotImports(ctrl *gomock.Controller) *MockWithDotImports {
mock := &MockWithDotImports{ctrl: ctrl}
mock.recorder = &MockWithDotImportsMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockWithDotImports) EXPECT() *MockWithDotImportsMockRecorder {
return m.recorder
}
// Method1 mocks base method
func (m *MockWithDotImports) Method1() Request {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Method1")
ret0, _ := ret[0].(Request)
return ret0
}
// Method1 indicates an expected call of Method1
func (mr *MockWithDotImportsMockRecorder) Method1() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Method1", reflect.TypeOf((*MockWithDotImports)(nil).Method1))
}
// Method2 mocks base method
func (m *MockWithDotImports) Method2() *bytes.Buffer {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Method2")
ret0, _ := ret[0].(*bytes.Buffer)
return ret0
}
// Method2 indicates an expected call of Method2
func (mr *MockWithDotImportsMockRecorder) Method2() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Method2", reflect.TypeOf((*MockWithDotImports)(nil).Method2))
}
// Method3 mocks base method
func (m *MockWithDotImports) Method3() Context {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Method3")
ret0, _ := ret[0].(Context)
return ret0
}
// Method3 indicates an expected call of Method3
func (mr *MockWithDotImportsMockRecorder) Method3() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Method3", reflect.TypeOf((*MockWithDotImports)(nil).Method3))
}

View File

@@ -0,0 +1,4 @@
//go:generate mockgen -package empty_interface -destination mock.go -source input.go
package empty_interface
type Empty interface{}

View File

@@ -0,0 +1,32 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: input.go
// Package empty_interface is a generated GoMock package.
package empty_interface
import (
gomock "github.com/golang/mock/gomock"
)
// MockEmpty is a mock of Empty interface
type MockEmpty struct {
ctrl *gomock.Controller
recorder *MockEmptyMockRecorder
}
// MockEmptyMockRecorder is the mock recorder for MockEmpty
type MockEmptyMockRecorder struct {
mock *MockEmpty
}
// NewMockEmpty creates a new mock instance
func NewMockEmpty(ctrl *gomock.Controller) *MockEmpty {
mock := &MockEmpty{ctrl: ctrl}
mock.recorder = &MockEmptyMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockEmpty) EXPECT() *MockEmptyMockRecorder {
return m.recorder
}

View File

@@ -0,0 +1,26 @@
The generated mock methods use some hardcoded variable/receiver names that can
have conflicts with the argument names that are defined by the code for which
the mock is generated when using the source generation method.
Example:
```go
type Example interface {
Method(_m, _mr, m, mr int)
}
```
```go
// Method mocks base method
func (_m *MockExample) Method(_m int, _mr int, m int, mr int) {
_m.ctrl.Call(_m, "Method", _m, _mr, m, mr)
}
```
In the above example one of the interface method parameters is called `_m`
but unfortunately the generated receiver name is also called `_m` so the
mock code won't compile.
The generator has to make sure that generated identifiers (e.g.: the receiver
names) are always different from the arg names that might come from external
sources.

View File

@@ -0,0 +1,16 @@
//go:generate mockgen -destination bugreport_mock.go -package bugreport -source=bugreport.go
package bugreport
type Example interface {
// _m and _mr were used by the buggy code: the '_' prefix was there hoping
// that no one will use method argument names starting with '_' reducing
// the chance of collision with generated identifiers.
// m and mr are used by the bugfixed new code, the '_' prefix has been
// removed because the new code generator changes the names of the
// generated identifiers in case they would collide with identifiers
// coming from argument names.
Method(_m, _mr, m, mr int)
VarargMethod(_s, _x, a, ret int, varargs ...int)
}

View File

@@ -0,0 +1,62 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: bugreport.go
// Package bugreport is a generated GoMock package.
package bugreport
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockExample is a mock of Example interface
type MockExample struct {
ctrl *gomock.Controller
recorder *MockExampleMockRecorder
}
// MockExampleMockRecorder is the mock recorder for MockExample
type MockExampleMockRecorder struct {
mock *MockExample
}
// NewMockExample creates a new mock instance
func NewMockExample(ctrl *gomock.Controller) *MockExample {
mock := &MockExample{ctrl: ctrl}
mock.recorder = &MockExampleMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockExample) EXPECT() *MockExampleMockRecorder {
return m.recorder
}
// Method mocks base method
func (m_2 *MockExample) Method(_m, _mr, m, mr int) {
m_2.ctrl.T.Helper()
m_2.ctrl.Call(m_2, "Method", _m, _mr, m, mr)
}
// Method indicates an expected call of Method
func (mr_2 *MockExampleMockRecorder) Method(_m, _mr, m, mr interface{}) *gomock.Call {
mr_2.mock.ctrl.T.Helper()
return mr_2.mock.ctrl.RecordCallWithMethodType(mr_2.mock, "Method", reflect.TypeOf((*MockExample)(nil).Method), _m, _mr, m, mr)
}
// VarargMethod mocks base method
func (m *MockExample) VarargMethod(_s, _x, a, ret int, varargs ...int) {
m.ctrl.T.Helper()
varargs_2 := []interface{}{_s, _x, a, ret}
for _, a_2 := range varargs {
varargs_2 = append(varargs_2, a_2)
}
m.ctrl.Call(m, "VarargMethod", varargs_2...)
}
// VarargMethod indicates an expected call of VarargMethod
func (mr *MockExampleMockRecorder) VarargMethod(_s, _x, a, ret interface{}, varargs ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs_2 := append([]interface{}{_s, _x, a, ret}, varargs...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VarargMethod", reflect.TypeOf((*MockExample)(nil).VarargMethod), varargs_2...)
}

View File

@@ -0,0 +1,26 @@
package bugreport
import (
"github.com/golang/mock/gomock"
"testing"
)
func TestExample_Method(t *testing.T) {
ctrl := gomock.NewController(t)
m := NewMockExample(ctrl)
m.EXPECT().Method(1, 2, 3, 4)
m.Method(1, 2, 3, 4)
ctrl.Finish()
}
func TestExample_VarargMethod(t *testing.T) {
ctrl := gomock.NewController(t)
m := NewMockExample(ctrl)
m.EXPECT().VarargMethod(1, 2, 3, 4, 6, 7)
m.VarargMethod(1, 2, 3, 4, 6, 7)
ctrl.Finish()
}

View File

@@ -0,0 +1,3 @@
Test the case where the generated code uses a type defined in the source package (in source mode). There are two test cases:
- the output is in a new package
- the output is in the same package as the input

View File

@@ -0,0 +1,9 @@
//go:generate mockgen -destination ../source_mock.go -source=source.go
//go:generate mockgen -package source -destination source_mock.go -source=source.go
package source
type X struct{}
type S interface {
F(X)
}

View File

@@ -0,0 +1,45 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: source.go
// Package source is a generated GoMock package.
package source
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockS is a mock of S interface
type MockS struct {
ctrl *gomock.Controller
recorder *MockSMockRecorder
}
// MockSMockRecorder is the mock recorder for MockS
type MockSMockRecorder struct {
mock *MockS
}
// NewMockS creates a new mock instance
func NewMockS(ctrl *gomock.Controller) *MockS {
mock := &MockS{ctrl: ctrl}
mock.recorder = &MockSMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockS) EXPECT() *MockSMockRecorder {
return m.recorder
}
// F mocks base method
func (m *MockS) F(arg0 X) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "F", arg0)
}
// F indicates an expected call of F
func (mr *MockSMockRecorder) F(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockS)(nil).F), arg0)
}

View File

@@ -0,0 +1,46 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: source.go
// Package mock_source is a generated GoMock package.
package mock_source
import (
gomock "github.com/golang/mock/gomock"
definition "github.com/golang/mock/mockgen/internal/tests/import_source/definition"
reflect "reflect"
)
// MockS is a mock of S interface
type MockS struct {
ctrl *gomock.Controller
recorder *MockSMockRecorder
}
// MockSMockRecorder is the mock recorder for MockS
type MockSMockRecorder struct {
mock *MockS
}
// NewMockS creates a new mock instance
func NewMockS(ctrl *gomock.Controller) *MockS {
mock := &MockS{ctrl: ctrl}
mock.recorder = &MockSMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockS) EXPECT() *MockSMockRecorder {
return m.recorder
}
// F mocks base method
func (m *MockS) F(arg0 definition.X) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "F", arg0)
}
// F indicates an expected call of F
func (mr *MockSMockRecorder) F(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "F", reflect.TypeOf((*MockS)(nil).F), arg0)
}

View File

@@ -0,0 +1,3 @@
//go:generate mockgen -destination subdir/internal/pkg/reflect_output/mock.go github.com/golang/mock/mockgen/internal/tests/internal_pkg/subdir/internal/pkg Intf
//go:generate mockgen -source subdir/internal/pkg/input.go -destination subdir/internal/pkg/source_output/mock.go
package test

View File

@@ -0,0 +1,16 @@
Test the case where the package has the `_test` suffix.
Prior to patch:
$ go generate
$ go test
# github.com/golang/mock/mockgen/internal/tests/mock_in_test_package_test [github.com/golang/mock/mockgen/internal/tests/mock_in_test_package.test]
./mock_test.go:36:44: undefined: User
./mock_test.go:38:21: undefined: User
FAIL github.com/golang/mock/mockgen/internal/tests/mock_in_test_package [build failed]
With this patch applied:
$ go generate
$ go test
ok github.com/golang/mock/mockgen/internal/tests/mock_in_test_package 0.031s

View File

@@ -0,0 +1,60 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: user.go
// Package users_test is a generated GoMock package.
package users_test
import (
gomock "github.com/golang/mock/gomock"
mock_in_test_package "github.com/golang/mock/mockgen/internal/tests/mock_in_test_package"
reflect "reflect"
)
// MockFinder is a mock of Finder interface
type MockFinder struct {
ctrl *gomock.Controller
recorder *MockFinderMockRecorder
}
// MockFinderMockRecorder is the mock recorder for MockFinder
type MockFinderMockRecorder struct {
mock *MockFinder
}
// NewMockFinder creates a new mock instance
func NewMockFinder(ctrl *gomock.Controller) *MockFinder {
mock := &MockFinder{ctrl: ctrl}
mock.recorder = &MockFinderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockFinder) EXPECT() *MockFinderMockRecorder {
return m.recorder
}
// FindUser mocks base method
func (m *MockFinder) FindUser(name string) mock_in_test_package.User {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindUser", name)
ret0, _ := ret[0].(mock_in_test_package.User)
return ret0
}
// FindUser indicates an expected call of FindUser
func (mr *MockFinderMockRecorder) FindUser(name interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindUser", reflect.TypeOf((*MockFinder)(nil).FindUser), name)
}
// Add mocks base method
func (m *MockFinder) Add(u mock_in_test_package.User) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Add", u)
}
// Add indicates an expected call of Add
func (mr *MockFinderMockRecorder) Add(u interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockFinder)(nil).Add), u)
}

View File

@@ -0,0 +1,12 @@
package users
//go:generate mockgen --source=user.go --destination=mock_test.go --package=users_test
type User struct {
Name string
}
type Finder interface {
FindUser(name string) User
Add(u User)
}

View File

@@ -0,0 +1 @@
package users

View File

@@ -0,0 +1,59 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: user_test.go
// Package users_test is a generated GoMock package.
package users_test
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockFinder is a mock of Finder interface
type MockFinder struct {
ctrl *gomock.Controller
recorder *MockFinderMockRecorder
}
// MockFinderMockRecorder is the mock recorder for MockFinder
type MockFinderMockRecorder struct {
mock *MockFinder
}
// NewMockFinder creates a new mock instance
func NewMockFinder(ctrl *gomock.Controller) *MockFinder {
mock := &MockFinder{ctrl: ctrl}
mock.recorder = &MockFinderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockFinder) EXPECT() *MockFinderMockRecorder {
return m.recorder
}
// FindUser mocks base method
func (m *MockFinder) FindUser(name string) User {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindUser", name)
ret0, _ := ret[0].(User)
return ret0
}
// FindUser indicates an expected call of FindUser
func (mr *MockFinderMockRecorder) FindUser(name interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindUser", reflect.TypeOf((*MockFinder)(nil).FindUser), name)
}
// Add mocks base method
func (m *MockFinder) Add(u User) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Add", u)
}
// Add indicates an expected call of Add
func (mr *MockFinderMockRecorder) Add(u interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Add", reflect.TypeOf((*MockFinder)(nil).Add), u)
}

View File

@@ -0,0 +1,12 @@
package users_test
//go:generate mockgen --source=user_test.go --destination=mock_test.go --package=users_test
type User struct {
Name string
}
type Finder interface {
FindUser(name string) User
Add(u User)
}

View File

@@ -0,0 +1 @@
From #52, this tests an unexported method in the mocked interface.

View File

@@ -0,0 +1,15 @@
//go:generate mockgen -destination bugreport_mock.go -package bugreport -source=bugreport.go Example
package bugreport
import "fmt"
// Example is an interface with a non exported method
type Example interface {
someMethod(string) string
}
// CallExample is a simple function that uses the interface
func CallExample(e Example) {
fmt.Println(e.someMethod("test"))
}

View File

@@ -0,0 +1,47 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: bugreport.go
// Package bugreport is a generated GoMock package.
package bugreport
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockExample is a mock of Example interface
type MockExample struct {
ctrl *gomock.Controller
recorder *MockExampleMockRecorder
}
// MockExampleMockRecorder is the mock recorder for MockExample
type MockExampleMockRecorder struct {
mock *MockExample
}
// NewMockExample creates a new mock instance
func NewMockExample(ctrl *gomock.Controller) *MockExample {
mock := &MockExample{ctrl: ctrl}
mock.recorder = &MockExampleMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockExample) EXPECT() *MockExampleMockRecorder {
return m.recorder
}
// someMethod mocks base method
func (m *MockExample) someMethod(arg0 string) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "someMethod", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// someMethod indicates an expected call of someMethod
func (mr *MockExampleMockRecorder) someMethod(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "someMethod", reflect.TypeOf((*MockExample)(nil).someMethod), arg0)
}

View File

@@ -0,0 +1,17 @@
package bugreport
import (
"testing"
"github.com/golang/mock/gomock"
)
func TestCallExample(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
e := NewMockExample(ctrl)
e.EXPECT().someMethod(gomock.Any()).Return("it works!")
CallExample(e)
}

View File

@@ -0,0 +1,2 @@
Test for [Issue#4](https://github.com/golang/mock/issues/4).
Also see discussion on [#28](https://github.com/golang/mock/pull/28).

View File

@@ -0,0 +1,4 @@
package vendor_dep
//go:generate mockgen -package vendor_dep -destination mock.go github.com/golang/mock/mockgen/internal/tests/vendor_dep VendorsDep
//go:generate mockgen -destination source_mock_package/mock.go -source=vendor_dep.go

View File

@@ -0,0 +1,48 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/golang/mock/mockgen/internal/tests/vendor_dep (interfaces: VendorsDep)
// Package vendor_dep is a generated GoMock package.
package vendor_dep
import (
gomock "github.com/golang/mock/gomock"
present "golang.org/x/tools/present"
reflect "reflect"
)
// MockVendorsDep is a mock of VendorsDep interface
type MockVendorsDep struct {
ctrl *gomock.Controller
recorder *MockVendorsDepMockRecorder
}
// MockVendorsDepMockRecorder is the mock recorder for MockVendorsDep
type MockVendorsDepMockRecorder struct {
mock *MockVendorsDep
}
// NewMockVendorsDep creates a new mock instance
func NewMockVendorsDep(ctrl *gomock.Controller) *MockVendorsDep {
mock := &MockVendorsDep{ctrl: ctrl}
mock.recorder = &MockVendorsDepMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockVendorsDep) EXPECT() *MockVendorsDepMockRecorder {
return m.recorder
}
// Foo mocks base method
func (m *MockVendorsDep) Foo() present.Elem {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Foo")
ret0, _ := ret[0].(present.Elem)
return ret0
}
// Foo indicates an expected call of Foo
func (mr *MockVendorsDepMockRecorder) Foo() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockVendorsDep)(nil).Foo))
}

View File

@@ -0,0 +1,48 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: vendor_dep.go
// Package mock_vendor_dep is a generated GoMock package.
package mock_vendor_dep
import (
gomock "github.com/golang/mock/gomock"
present "golang.org/x/tools/present"
reflect "reflect"
)
// MockVendorsDep is a mock of VendorsDep interface
type MockVendorsDep struct {
ctrl *gomock.Controller
recorder *MockVendorsDepMockRecorder
}
// MockVendorsDepMockRecorder is the mock recorder for MockVendorsDep
type MockVendorsDepMockRecorder struct {
mock *MockVendorsDep
}
// NewMockVendorsDep creates a new mock instance
func NewMockVendorsDep(ctrl *gomock.Controller) *MockVendorsDep {
mock := &MockVendorsDep{ctrl: ctrl}
mock.recorder = &MockVendorsDepMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockVendorsDep) EXPECT() *MockVendorsDepMockRecorder {
return m.recorder
}
// Foo mocks base method
func (m *MockVendorsDep) Foo() present.Elem {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Foo")
ret0, _ := ret[0].(present.Elem)
return ret0
}
// Foo indicates an expected call of Foo
func (mr *MockVendorsDepMockRecorder) Foo() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Foo", reflect.TypeOf((*MockVendorsDep)(nil).Foo))
}

View File

@@ -0,0 +1,7 @@
package vendor_dep
import "golang.org/x/tools/present"
type VendorsDep interface {
Foo() present.Elem
}

View File

@@ -0,0 +1 @@
Test for [Issue#4](https://github.com/golang/mock/issues/4).

View File

@@ -0,0 +1,3 @@
package vendor_pkg
//go:generate mockgen -destination mock.go -package vendor_pkg golang.org/x/tools/present Elem

View File

@@ -0,0 +1,47 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: golang.org/x/tools/present (interfaces: Elem)
// Package vendor_pkg is a generated GoMock package.
package vendor_pkg
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockElem is a mock of Elem interface
type MockElem struct {
ctrl *gomock.Controller
recorder *MockElemMockRecorder
}
// MockElemMockRecorder is the mock recorder for MockElem
type MockElemMockRecorder struct {
mock *MockElem
}
// NewMockElem creates a new mock instance
func NewMockElem(ctrl *gomock.Controller) *MockElem {
mock := &MockElem{ctrl: ctrl}
mock.recorder = &MockElemMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockElem) EXPECT() *MockElemMockRecorder {
return m.recorder
}
// TemplateName mocks base method
func (m *MockElem) TemplateName() string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "TemplateName")
ret0, _ := ret[0].(string)
return ret0
}
// TemplateName indicates an expected call of TemplateName
func (mr *MockElemMockRecorder) TemplateName() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TemplateName", reflect.TypeOf((*MockElem)(nil).TemplateName))
}

588
vendor/github.com/golang/mock/mockgen/mockgen.go generated vendored Normal file
View File

@@ -0,0 +1,588 @@
// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// MockGen generates mock implementations of Go interfaces.
package main
// TODO: This does not support recursive embedded interfaces.
// TODO: This does not support embedding package-local interfaces in a separate file.
import (
"bytes"
"flag"
"fmt"
"go/build"
"go/format"
"go/token"
"io"
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"sort"
"strconv"
"strings"
"unicode"
"github.com/golang/mock/mockgen/model"
)
const (
gomockImportPath = "github.com/golang/mock/gomock"
)
var (
source = flag.String("source", "", "(source mode) Input Go source file; enables source mode.")
destination = flag.String("destination", "", "Output file; defaults to stdout.")
mockNames = flag.String("mock_names", "", "Comma-separated interfaceName=mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix.")
packageOut = flag.String("package", "", "Package of the generated code; defaults to the package of the input with a 'mock_' prefix.")
selfPackage = flag.String("self_package", "", "The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.")
writePkgComment = flag.Bool("write_package_comment", true, "Writes package documentation comment (godoc) if true.")
copyrightFile = flag.String("copyright_file", "", "Copyright file used to add copyright header")
debugParser = flag.Bool("debug_parser", false, "Print out parser results only.")
)
func main() {
flag.Usage = usage
flag.Parse()
var pkg *model.Package
var err error
if *source != "" {
pkg, err = parseFile(*source)
} else {
if flag.NArg() != 2 {
usage()
log.Fatal("Expected exactly two arguments")
}
pkg, err = reflect(flag.Arg(0), strings.Split(flag.Arg(1), ","))
}
if err != nil {
log.Fatalf("Loading input failed: %v", err)
}
if *debugParser {
pkg.Print(os.Stdout)
return
}
dst := os.Stdout
if len(*destination) > 0 {
if err := os.MkdirAll(filepath.Dir(*destination), os.ModePerm); err != nil {
log.Fatalf("Unable to create directory: %v", err)
}
f, err := os.Create(*destination)
if err != nil {
log.Fatalf("Failed opening destination file: %v", err)
}
defer f.Close()
dst = f
}
packageName := *packageOut
if packageName == "" {
// pkg.Name in reflect mode is the base name of the import path,
// which might have characters that are illegal to have in package names.
packageName = "mock_" + sanitize(pkg.Name)
}
// outputPackagePath represents the fully qualified name of the package of
// the generated code. Its purposes are to prevent the module from importing
// itself and to prevent qualifying type names that come from its own
// package (i.e. if there is a type called X then we want to print "X" not
// "package.X" since "package" is this package). This can happen if the mock
// is output into an already existing package.
outputPackagePath := *selfPackage
if len(outputPackagePath) == 0 && len(*destination) > 0 {
dst, _ := filepath.Abs(filepath.Dir(*destination))
for _, prefix := range build.Default.SrcDirs() {
if strings.HasPrefix(dst, prefix) {
if rel, err := filepath.Rel(prefix, dst); err == nil {
outputPackagePath = rel
break
}
}
}
}
g := new(generator)
if *source != "" {
g.filename = *source
} else {
g.srcPackage = flag.Arg(0)
g.srcInterfaces = flag.Arg(1)
}
if *mockNames != "" {
g.mockNames = parseMockNames(*mockNames)
}
if *copyrightFile != "" {
header, err := ioutil.ReadFile(*copyrightFile)
if err != nil {
log.Fatalf("Failed reading copyright file: %v", err)
}
g.copyrightHeader = string(header)
}
if err := g.Generate(pkg, packageName, outputPackagePath); err != nil {
log.Fatalf("Failed generating mock: %v", err)
}
if _, err := dst.Write(g.Output()); err != nil {
log.Fatalf("Failed writing to destination: %v", err)
}
}
func parseMockNames(names string) map[string]string {
mocksMap := make(map[string]string)
for _, kv := range strings.Split(names, ",") {
parts := strings.SplitN(kv, "=", 2)
if len(parts) != 2 || parts[1] == "" {
log.Fatalf("bad mock names spec: %v", kv)
}
mocksMap[parts[0]] = parts[1]
}
return mocksMap
}
func usage() {
io.WriteString(os.Stderr, usageText)
flag.PrintDefaults()
}
const usageText = `mockgen has two modes of operation: source and reflect.
Source mode generates mock interfaces from a source file.
It is enabled by using the -source flag. Other flags that
may be useful in this mode are -imports and -aux_files.
Example:
mockgen -source=foo.go [other options]
Reflect mode generates mock interfaces by building a program
that uses reflection to understand interfaces. It is enabled
by passing two non-flag arguments: an import path, and a
comma-separated list of symbols.
Example:
mockgen database/sql/driver Conn,Driver
`
type generator struct {
buf bytes.Buffer
indent string
mockNames map[string]string // may be empty
filename string // may be empty
srcPackage, srcInterfaces string // may be empty
copyrightHeader string
packageMap map[string]string // map from import path to package name
}
func (g *generator) p(format string, args ...interface{}) {
fmt.Fprintf(&g.buf, g.indent+format+"\n", args...)
}
func (g *generator) in() {
g.indent += "\t"
}
func (g *generator) out() {
if len(g.indent) > 0 {
g.indent = g.indent[0 : len(g.indent)-1]
}
}
func removeDot(s string) string {
if len(s) > 0 && s[len(s)-1] == '.' {
return s[0 : len(s)-1]
}
return s
}
// sanitize cleans up a string to make a suitable package name.
func sanitize(s string) string {
t := ""
for _, r := range s {
if t == "" {
if unicode.IsLetter(r) || r == '_' {
t += string(r)
continue
}
} else {
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' {
t += string(r)
continue
}
}
t += "_"
}
if t == "_" {
t = "x"
}
return t
}
func (g *generator) Generate(pkg *model.Package, pkgName string, outputPackagePath string) error {
if pkgName != pkg.Name {
outputPackagePath = ""
}
if g.copyrightHeader != "" {
lines := strings.Split(g.copyrightHeader, "\n")
for _, line := range lines {
g.p("// %s", line)
}
g.p("")
}
g.p("// Code generated by MockGen. DO NOT EDIT.")
if g.filename != "" {
g.p("// Source: %v", g.filename)
} else {
g.p("// Source: %v (interfaces: %v)", g.srcPackage, g.srcInterfaces)
}
g.p("")
// Get all required imports, and generate unique names for them all.
im := pkg.Imports()
im[gomockImportPath] = true
// Only import reflect if it's used. We only use reflect in mocked methods
// so only import if any of the mocked interfaces have methods.
for _, intf := range pkg.Interfaces {
if len(intf.Methods) > 0 {
im["reflect"] = true
break
}
}
// Sort keys to make import alias generation predictable
sortedPaths := make([]string, len(im), len(im))
x := 0
for pth := range im {
sortedPaths[x] = pth
x++
}
sort.Strings(sortedPaths)
g.packageMap = make(map[string]string, len(im))
localNames := make(map[string]bool, len(im))
for _, pth := range sortedPaths {
base := sanitize(path.Base(pth))
// Local names for an imported package can usually be the basename of the import path.
// A couple of situations don't permit that, such as duplicate local names
// (e.g. importing "html/template" and "text/template"), or where the basename is
// a keyword (e.g. "foo/case").
// try base0, base1, ...
pkgName := base
i := 0
for localNames[pkgName] || token.Lookup(pkgName).IsKeyword() {
pkgName = base + strconv.Itoa(i)
i++
}
g.packageMap[pth] = pkgName
localNames[pkgName] = true
}
if *writePkgComment {
g.p("// Package %v is a generated GoMock package.", pkgName)
}
g.p("package %v", pkgName)
g.p("")
g.p("import (")
g.in()
for path, pkg := range g.packageMap {
if path == outputPackagePath {
continue
}
g.p("%v %q", pkg, path)
}
for _, path := range pkg.DotImports {
g.p(". %q", path)
}
g.out()
g.p(")")
for _, intf := range pkg.Interfaces {
if err := g.GenerateMockInterface(intf, outputPackagePath); err != nil {
return err
}
}
return nil
}
// The name of the mock type to use for the given interface identifier.
func (g *generator) mockName(typeName string) string {
if mockName, ok := g.mockNames[typeName]; ok {
return mockName
}
return "Mock" + typeName
}
func (g *generator) GenerateMockInterface(intf *model.Interface, outputPackagePath string) error {
mockType := g.mockName(intf.Name)
g.p("")
g.p("// %v is a mock of %v interface", mockType, intf.Name)
g.p("type %v struct {", mockType)
g.in()
g.p("ctrl *gomock.Controller")
g.p("recorder *%vMockRecorder", mockType)
g.out()
g.p("}")
g.p("")
g.p("// %vMockRecorder is the mock recorder for %v", mockType, mockType)
g.p("type %vMockRecorder struct {", mockType)
g.in()
g.p("mock *%v", mockType)
g.out()
g.p("}")
g.p("")
// TODO: Re-enable this if we can import the interface reliably.
//g.p("// Verify that the mock satisfies the interface at compile time.")
//g.p("var _ %v = (*%v)(nil)", typeName, mockType)
//g.p("")
g.p("// New%v creates a new mock instance", mockType)
g.p("func New%v(ctrl *gomock.Controller) *%v {", mockType, mockType)
g.in()
g.p("mock := &%v{ctrl: ctrl}", mockType)
g.p("mock.recorder = &%vMockRecorder{mock}", mockType)
g.p("return mock")
g.out()
g.p("}")
g.p("")
// XXX: possible name collision here if someone has EXPECT in their interface.
g.p("// EXPECT returns an object that allows the caller to indicate expected use")
g.p("func (m *%v) EXPECT() *%vMockRecorder {", mockType, mockType)
g.in()
g.p("return m.recorder")
g.out()
g.p("}")
g.GenerateMockMethods(mockType, intf, outputPackagePath)
return nil
}
func (g *generator) GenerateMockMethods(mockType string, intf *model.Interface, pkgOverride string) {
for _, m := range intf.Methods {
g.p("")
g.GenerateMockMethod(mockType, m, pkgOverride)
g.p("")
g.GenerateMockRecorderMethod(mockType, m)
}
}
func makeArgString(argNames, argTypes []string) string {
args := make([]string, len(argNames))
for i, name := range argNames {
// specify the type only once for consecutive args of the same type
if i+1 < len(argTypes) && argTypes[i] == argTypes[i+1] {
args[i] = name
} else {
args[i] = name + " " + argTypes[i]
}
}
return strings.Join(args, ", ")
}
// GenerateMockMethod generates a mock method implementation.
// If non-empty, pkgOverride is the package in which unqualified types reside.
func (g *generator) GenerateMockMethod(mockType string, m *model.Method, pkgOverride string) error {
argNames := g.getArgNames(m)
argTypes := g.getArgTypes(m, pkgOverride)
argString := makeArgString(argNames, argTypes)
rets := make([]string, len(m.Out))
for i, p := range m.Out {
rets[i] = p.Type.String(g.packageMap, pkgOverride)
}
retString := strings.Join(rets, ", ")
if len(rets) > 1 {
retString = "(" + retString + ")"
}
if retString != "" {
retString = " " + retString
}
ia := newIdentifierAllocator(argNames)
idRecv := ia.allocateIdentifier("m")
g.p("// %v mocks base method", m.Name)
g.p("func (%v *%v) %v(%v)%v {", idRecv, mockType, m.Name, argString, retString)
g.in()
g.p("%s.ctrl.T.Helper()", idRecv)
var callArgs string
if m.Variadic == nil {
if len(argNames) > 0 {
callArgs = ", " + strings.Join(argNames, ", ")
}
} else {
// Non-trivial. The generated code must build a []interface{},
// but the variadic argument may be any type.
idVarArgs := ia.allocateIdentifier("varargs")
idVArg := ia.allocateIdentifier("a")
g.p("%s := []interface{}{%s}", idVarArgs, strings.Join(argNames[:len(argNames)-1], ", "))
g.p("for _, %s := range %s {", idVArg, argNames[len(argNames)-1])
g.in()
g.p("%s = append(%s, %s)", idVarArgs, idVarArgs, idVArg)
g.out()
g.p("}")
callArgs = ", " + idVarArgs + "..."
}
if len(m.Out) == 0 {
g.p(`%v.ctrl.Call(%v, %q%v)`, idRecv, idRecv, m.Name, callArgs)
} else {
idRet := ia.allocateIdentifier("ret")
g.p(`%v := %v.ctrl.Call(%v, %q%v)`, idRet, idRecv, idRecv, m.Name, callArgs)
// Go does not allow "naked" type assertions on nil values, so we use the two-value form here.
// The value of that is either (x.(T), true) or (Z, false), where Z is the zero value for T.
// Happily, this coincides with the semantics we want here.
retNames := make([]string, len(rets))
for i, t := range rets {
retNames[i] = ia.allocateIdentifier(fmt.Sprintf("ret%d", i))
g.p("%s, _ := %s[%d].(%s)", retNames[i], idRet, i, t)
}
g.p("return " + strings.Join(retNames, ", "))
}
g.out()
g.p("}")
return nil
}
func (g *generator) GenerateMockRecorderMethod(mockType string, m *model.Method) error {
argNames := g.getArgNames(m)
var argString string
if m.Variadic == nil {
argString = strings.Join(argNames, ", ")
} else {
argString = strings.Join(argNames[:len(argNames)-1], ", ")
}
if argString != "" {
argString += " interface{}"
}
if m.Variadic != nil {
if argString != "" {
argString += ", "
}
argString += fmt.Sprintf("%s ...interface{}", argNames[len(argNames)-1])
}
ia := newIdentifierAllocator(argNames)
idRecv := ia.allocateIdentifier("mr")
g.p("// %v indicates an expected call of %v", m.Name, m.Name)
g.p("func (%s *%vMockRecorder) %v(%v) *gomock.Call {", idRecv, mockType, m.Name, argString)
g.in()
g.p("%s.mock.ctrl.T.Helper()", idRecv)
var callArgs string
if m.Variadic == nil {
if len(argNames) > 0 {
callArgs = ", " + strings.Join(argNames, ", ")
}
} else {
if len(argNames) == 1 {
// Easy: just use ... to push the arguments through.
callArgs = ", " + argNames[0] + "..."
} else {
// Hard: create a temporary slice.
idVarArgs := ia.allocateIdentifier("varargs")
g.p("%s := append([]interface{}{%s}, %s...)",
idVarArgs,
strings.Join(argNames[:len(argNames)-1], ", "),
argNames[len(argNames)-1])
callArgs = ", " + idVarArgs + "..."
}
}
g.p(`return %s.mock.ctrl.RecordCallWithMethodType(%s.mock, "%s", reflect.TypeOf((*%s)(nil).%s)%s)`, idRecv, idRecv, m.Name, mockType, m.Name, callArgs)
g.out()
g.p("}")
return nil
}
func (g *generator) getArgNames(m *model.Method) []string {
argNames := make([]string, len(m.In))
for i, p := range m.In {
name := p.Name
if name == "" {
name = fmt.Sprintf("arg%d", i)
}
argNames[i] = name
}
if m.Variadic != nil {
name := m.Variadic.Name
if name == "" {
name = fmt.Sprintf("arg%d", len(m.In))
}
argNames = append(argNames, name)
}
return argNames
}
func (g *generator) getArgTypes(m *model.Method, pkgOverride string) []string {
argTypes := make([]string, len(m.In))
for i, p := range m.In {
argTypes[i] = p.Type.String(g.packageMap, pkgOverride)
}
if m.Variadic != nil {
argTypes = append(argTypes, "..."+m.Variadic.Type.String(g.packageMap, pkgOverride))
}
return argTypes
}
type identifierAllocator map[string]struct{}
func newIdentifierAllocator(taken []string) identifierAllocator {
a := make(identifierAllocator, len(taken))
for _, s := range taken {
a[s] = struct{}{}
}
return a
}
func (o identifierAllocator) allocateIdentifier(want string) string {
id := want
for i := 2; ; i++ {
if _, ok := o[id]; !ok {
o[id] = struct{}{}
return id
}
id = want + "_" + strconv.Itoa(i)
}
}
// Output returns the generator's output, formatted in the standard Go style.
func (g *generator) Output() []byte {
src, err := format.Source(g.buf.Bytes())
if err != nil {
log.Fatalf("Failed to format generated source code: %s\n%s", err, g.buf.String())
}
return src
}

269
vendor/github.com/golang/mock/mockgen/mockgen_test.go generated vendored Normal file
View File

@@ -0,0 +1,269 @@
package main
import (
"fmt"
"regexp"
"strings"
"testing"
"github.com/golang/mock/mockgen/model"
)
func TestMakeArgString(t *testing.T) {
testCases := []struct {
argNames []string
argTypes []string
argString string
}{
{
argNames: nil,
argTypes: nil,
argString: "",
},
{
argNames: []string{"arg0"},
argTypes: []string{"int"},
argString: "arg0 int",
},
{
argNames: []string{"arg0", "arg1"},
argTypes: []string{"int", "bool"},
argString: "arg0 int, arg1 bool",
},
{
argNames: []string{"arg0", "arg1"},
argTypes: []string{"int", "int"},
argString: "arg0, arg1 int",
},
{
argNames: []string{"arg0", "arg1", "arg2"},
argTypes: []string{"bool", "int", "int"},
argString: "arg0 bool, arg1, arg2 int",
},
{
argNames: []string{"arg0", "arg1", "arg2"},
argTypes: []string{"int", "bool", "int"},
argString: "arg0 int, arg1 bool, arg2 int",
},
{
argNames: []string{"arg0", "arg1", "arg2"},
argTypes: []string{"int", "int", "bool"},
argString: "arg0, arg1 int, arg2 bool",
},
{
argNames: []string{"arg0", "arg1", "arg2"},
argTypes: []string{"int", "int", "int"},
argString: "arg0, arg1, arg2 int",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3"},
argTypes: []string{"bool", "int", "int", "int"},
argString: "arg0 bool, arg1, arg2, arg3 int",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3"},
argTypes: []string{"int", "bool", "int", "int"},
argString: "arg0 int, arg1 bool, arg2, arg3 int",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3"},
argTypes: []string{"int", "int", "bool", "int"},
argString: "arg0, arg1 int, arg2 bool, arg3 int",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3"},
argTypes: []string{"int", "int", "int", "bool"},
argString: "arg0, arg1, arg2 int, arg3 bool",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
argTypes: []string{"bool", "int", "int", "int", "bool"},
argString: "arg0 bool, arg1, arg2, arg3 int, arg4 bool",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
argTypes: []string{"int", "bool", "int", "int", "bool"},
argString: "arg0 int, arg1 bool, arg2, arg3 int, arg4 bool",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
argTypes: []string{"int", "int", "bool", "int", "bool"},
argString: "arg0, arg1 int, arg2 bool, arg3 int, arg4 bool",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
argTypes: []string{"int", "int", "int", "bool", "bool"},
argString: "arg0, arg1, arg2 int, arg3, arg4 bool",
},
{
argNames: []string{"arg0", "arg1", "arg2", "arg3", "arg4"},
argTypes: []string{"int", "int", "bool", "bool", "int"},
argString: "arg0, arg1 int, arg2, arg3 bool, arg4 int",
},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
s := makeArgString(tc.argNames, tc.argTypes)
if s != tc.argString {
t.Errorf("result == %q, want %q", s, tc.argString)
}
})
}
}
func TestNewIdentifierAllocator(t *testing.T) {
a := newIdentifierAllocator([]string{"taken1", "taken2"})
if len(a) != 2 {
t.Fatalf("expected 2 items, got %v", len(a))
}
_, ok := a["taken1"]
if !ok {
t.Errorf("allocator doesn't contain 'taken1': %#v", a)
}
_, ok = a["taken2"]
if !ok {
t.Errorf("allocator doesn't contain 'taken2': %#v", a)
}
}
func allocatorContainsIdentifiers(a identifierAllocator, ids []string) bool {
if len(a) != len(ids) {
return false
}
for _, id := range ids {
_, ok := a[id]
if !ok {
return false
}
}
return true
}
func TestIdentifierAllocator_allocateIdentifier(t *testing.T) {
a := newIdentifierAllocator([]string{"taken"})
t2 := a.allocateIdentifier("taken_2")
if t2 != "taken_2" {
t.Fatalf("expected 'taken_2', got %q", t2)
}
expected := []string{"taken", "taken_2"}
if !allocatorContainsIdentifiers(a, expected) {
t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
}
t3 := a.allocateIdentifier("taken")
if t3 != "taken_3" {
t.Fatalf("expected 'taken_3', got %q", t3)
}
expected = []string{"taken", "taken_2", "taken_3"}
if !allocatorContainsIdentifiers(a, expected) {
t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
}
t4 := a.allocateIdentifier("taken")
if t4 != "taken_4" {
t.Fatalf("expected 'taken_4', got %q", t4)
}
expected = []string{"taken", "taken_2", "taken_3", "taken_4"}
if !allocatorContainsIdentifiers(a, expected) {
t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
}
id := a.allocateIdentifier("id")
if id != "id" {
t.Fatalf("expected 'id', got %q", id)
}
expected = []string{"taken", "taken_2", "taken_3", "taken_4", "id"}
if !allocatorContainsIdentifiers(a, expected) {
t.Fatalf("allocator doesn't contain the expected items - allocator: %#v, expected items: %#v", a, expected)
}
}
func TestGenerateMockInterface_Helper(t *testing.T) {
for _, test := range []struct {
Name string
Identifier string
HelperLine string
Methods []*model.Method
}{
{Name: "mock", Identifier: "MockSomename", HelperLine: "m.ctrl.T.Helper()"},
{Name: "recorder", Identifier: "MockSomenameMockRecorder", HelperLine: "mr.mock.ctrl.T.Helper()"},
{
Name: "mock identifier conflict",
Identifier: "MockSomename",
HelperLine: "m_2.ctrl.T.Helper()",
Methods: []*model.Method{
{
Name: "MethodA",
In: []*model.Parameter{
{
Name: "m",
Type: &model.NamedType{Type: "int"},
},
},
},
},
},
{
Name: "recorder identifier conflict",
Identifier: "MockSomenameMockRecorder",
HelperLine: "mr_2.mock.ctrl.T.Helper()",
Methods: []*model.Method{
{
Name: "MethodA",
In: []*model.Parameter{
{
Name: "mr",
Type: &model.NamedType{Type: "int"},
},
},
},
},
},
} {
t.Run(test.Name, func(t *testing.T) {
g := generator{}
if len(test.Methods) == 0 {
test.Methods = []*model.Method{
{Name: "MethodA"},
{Name: "MethodB"},
}
}
if err := g.GenerateMockInterface(&model.Interface{
Name: "Somename",
Methods: test.Methods,
}, "somepackage"); err != nil {
t.Fatal(err)
}
lines := strings.Split(g.buf.String(), "\n")
// T.Helper() should be the first line
for _, method := range test.Methods {
if strings.TrimSpace(lines[findMethod(t, test.Identifier, method.Name, lines)+1]) != test.HelperLine {
t.Fatalf("method %s.%s did not declare itself a Helper method", test.Identifier, method.Name)
}
}
})
}
}
func findMethod(t *testing.T, identifier, methodName string, lines []string) int {
t.Helper()
r := regexp.MustCompile(fmt.Sprintf(`func\s+\(.+%s\)\s*%s`, identifier, methodName))
for i, line := range lines {
if r.MatchString(line) {
return i
}
}
t.Fatalf("unable to find 'func (m %s) %s'", identifier, methodName)
panic("unreachable")
}

454
vendor/github.com/golang/mock/mockgen/model/model.go generated vendored Normal file
View File

@@ -0,0 +1,454 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package model contains the data model necessary for generating mock implementations.
package model
import (
"encoding/gob"
"fmt"
"io"
"reflect"
"strings"
)
// pkgPath is the importable path for package model
const pkgPath = "github.com/golang/mock/mockgen/model"
// Package is a Go package. It may be a subset.
type Package struct {
Name string
Interfaces []*Interface
DotImports []string
}
func (pkg *Package) Print(w io.Writer) {
fmt.Fprintf(w, "package %s\n", pkg.Name)
for _, intf := range pkg.Interfaces {
intf.Print(w)
}
}
// Imports returns the imports needed by the Package as a set of import paths.
func (pkg *Package) Imports() map[string]bool {
im := make(map[string]bool)
for _, intf := range pkg.Interfaces {
intf.addImports(im)
}
return im
}
// Interface is a Go interface.
type Interface struct {
Name string
Methods []*Method
}
func (intf *Interface) Print(w io.Writer) {
fmt.Fprintf(w, "interface %s\n", intf.Name)
for _, m := range intf.Methods {
m.Print(w)
}
}
func (intf *Interface) addImports(im map[string]bool) {
for _, m := range intf.Methods {
m.addImports(im)
}
}
// Method is a single method of an interface.
type Method struct {
Name string
In, Out []*Parameter
Variadic *Parameter // may be nil
}
func (m *Method) Print(w io.Writer) {
fmt.Fprintf(w, " - method %s\n", m.Name)
if len(m.In) > 0 {
fmt.Fprintf(w, " in:\n")
for _, p := range m.In {
p.Print(w)
}
}
if m.Variadic != nil {
fmt.Fprintf(w, " ...:\n")
m.Variadic.Print(w)
}
if len(m.Out) > 0 {
fmt.Fprintf(w, " out:\n")
for _, p := range m.Out {
p.Print(w)
}
}
}
func (m *Method) addImports(im map[string]bool) {
for _, p := range m.In {
p.Type.addImports(im)
}
if m.Variadic != nil {
m.Variadic.Type.addImports(im)
}
for _, p := range m.Out {
p.Type.addImports(im)
}
}
// Parameter is an argument or return parameter of a method.
type Parameter struct {
Name string // may be empty
Type Type
}
func (p *Parameter) Print(w io.Writer) {
n := p.Name
if n == "" {
n = `""`
}
fmt.Fprintf(w, " - %v: %v\n", n, p.Type.String(nil, ""))
}
// Type is a Go type.
type Type interface {
String(pm map[string]string, pkgOverride string) string
addImports(im map[string]bool)
}
func init() {
gob.Register(&ArrayType{})
gob.Register(&ChanType{})
gob.Register(&FuncType{})
gob.Register(&MapType{})
gob.Register(&NamedType{})
gob.Register(&PointerType{})
// Call gob.RegisterName to make sure it has the consistent name registered
// for both gob decoder and encoder.
//
// For a non-pointer type, gob.Register will try to get package full path by
// calling rt.PkgPath() for a name to register. If your project has vendor
// directory, it is possible that PkgPath will get a path like this:
// ../../../vendor/github.com/golang/mock/mockgen/model
gob.RegisterName(pkgPath+".PredeclaredType", PredeclaredType(""))
}
// ArrayType is an array or slice type.
type ArrayType struct {
Len int // -1 for slices, >= 0 for arrays
Type Type
}
func (at *ArrayType) String(pm map[string]string, pkgOverride string) string {
s := "[]"
if at.Len > -1 {
s = fmt.Sprintf("[%d]", at.Len)
}
return s + at.Type.String(pm, pkgOverride)
}
func (at *ArrayType) addImports(im map[string]bool) { at.Type.addImports(im) }
// ChanType is a channel type.
type ChanType struct {
Dir ChanDir // 0, 1 or 2
Type Type
}
func (ct *ChanType) String(pm map[string]string, pkgOverride string) string {
s := ct.Type.String(pm, pkgOverride)
if ct.Dir == RecvDir {
return "<-chan " + s
}
if ct.Dir == SendDir {
return "chan<- " + s
}
return "chan " + s
}
func (ct *ChanType) addImports(im map[string]bool) { ct.Type.addImports(im) }
// ChanDir is a channel direction.
type ChanDir int
const (
RecvDir ChanDir = 1
SendDir ChanDir = 2
)
// FuncType is a function type.
type FuncType struct {
In, Out []*Parameter
Variadic *Parameter // may be nil
}
func (ft *FuncType) String(pm map[string]string, pkgOverride string) string {
args := make([]string, len(ft.In))
for i, p := range ft.In {
args[i] = p.Type.String(pm, pkgOverride)
}
if ft.Variadic != nil {
args = append(args, "..."+ft.Variadic.Type.String(pm, pkgOverride))
}
rets := make([]string, len(ft.Out))
for i, p := range ft.Out {
rets[i] = p.Type.String(pm, pkgOverride)
}
retString := strings.Join(rets, ", ")
if nOut := len(ft.Out); nOut == 1 {
retString = " " + retString
} else if nOut > 1 {
retString = " (" + retString + ")"
}
return "func(" + strings.Join(args, ", ") + ")" + retString
}
func (ft *FuncType) addImports(im map[string]bool) {
for _, p := range ft.In {
p.Type.addImports(im)
}
if ft.Variadic != nil {
ft.Variadic.Type.addImports(im)
}
for _, p := range ft.Out {
p.Type.addImports(im)
}
}
// MapType is a map type.
type MapType struct {
Key, Value Type
}
func (mt *MapType) String(pm map[string]string, pkgOverride string) string {
return "map[" + mt.Key.String(pm, pkgOverride) + "]" + mt.Value.String(pm, pkgOverride)
}
func (mt *MapType) addImports(im map[string]bool) {
mt.Key.addImports(im)
mt.Value.addImports(im)
}
// NamedType is an exported type in a package.
type NamedType struct {
Package string // may be empty
Type string // TODO: should this be typed Type?
}
func (nt *NamedType) String(pm map[string]string, pkgOverride string) string {
// TODO: is this right?
if pkgOverride == nt.Package {
return nt.Type
}
prefix := pm[nt.Package]
if prefix != "" {
return prefix + "." + nt.Type
} else {
return nt.Type
}
}
func (nt *NamedType) addImports(im map[string]bool) {
if nt.Package != "" {
im[nt.Package] = true
}
}
// PointerType is a pointer to another type.
type PointerType struct {
Type Type
}
func (pt *PointerType) String(pm map[string]string, pkgOverride string) string {
return "*" + pt.Type.String(pm, pkgOverride)
}
func (pt *PointerType) addImports(im map[string]bool) { pt.Type.addImports(im) }
// PredeclaredType is a predeclared type such as "int".
type PredeclaredType string
func (pt PredeclaredType) String(pm map[string]string, pkgOverride string) string { return string(pt) }
func (pt PredeclaredType) addImports(im map[string]bool) {}
// The following code is intended to be called by the program generated by ../reflect.go.
func InterfaceFromInterfaceType(it reflect.Type) (*Interface, error) {
if it.Kind() != reflect.Interface {
return nil, fmt.Errorf("%v is not an interface", it)
}
intf := &Interface{}
for i := 0; i < it.NumMethod(); i++ {
mt := it.Method(i)
// TODO: need to skip unexported methods? or just raise an error?
m := &Method{
Name: mt.Name,
}
var err error
m.In, m.Variadic, m.Out, err = funcArgsFromType(mt.Type)
if err != nil {
return nil, err
}
intf.Methods = append(intf.Methods, m)
}
return intf, nil
}
// t's Kind must be a reflect.Func.
func funcArgsFromType(t reflect.Type) (in []*Parameter, variadic *Parameter, out []*Parameter, err error) {
nin := t.NumIn()
if t.IsVariadic() {
nin--
}
var p *Parameter
for i := 0; i < nin; i++ {
p, err = parameterFromType(t.In(i))
if err != nil {
return
}
in = append(in, p)
}
if t.IsVariadic() {
p, err = parameterFromType(t.In(nin).Elem())
if err != nil {
return
}
variadic = p
}
for i := 0; i < t.NumOut(); i++ {
p, err = parameterFromType(t.Out(i))
if err != nil {
return
}
out = append(out, p)
}
return
}
func parameterFromType(t reflect.Type) (*Parameter, error) {
tt, err := typeFromType(t)
if err != nil {
return nil, err
}
return &Parameter{Type: tt}, nil
}
var errorType = reflect.TypeOf((*error)(nil)).Elem()
var byteType = reflect.TypeOf(byte(0))
func typeFromType(t reflect.Type) (Type, error) {
// Hack workaround for https://golang.org/issue/3853.
// This explicit check should not be necessary.
if t == byteType {
return PredeclaredType("byte"), nil
}
if imp := t.PkgPath(); imp != "" {
// PkgPath might return a path that includes "vendor"
// These paths do not compile, so we need to remove everything
// up to and including "/vendor/"
// see https://github.com/golang/go/issues/12019
if i := strings.LastIndex(imp, "/vendor/"); i != -1 {
imp = imp[i+len("/vendor/"):]
}
return &NamedType{
Package: imp,
Type: t.Name(),
}, nil
}
// only unnamed or predeclared types after here
// Lots of types have element types. Let's do the parsing and error checking for all of them.
var elemType Type
switch t.Kind() {
case reflect.Array, reflect.Chan, reflect.Map, reflect.Ptr, reflect.Slice:
var err error
elemType, err = typeFromType(t.Elem())
if err != nil {
return nil, err
}
}
switch t.Kind() {
case reflect.Array:
return &ArrayType{
Len: t.Len(),
Type: elemType,
}, nil
case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.String:
return PredeclaredType(t.Kind().String()), nil
case reflect.Chan:
var dir ChanDir
switch t.ChanDir() {
case reflect.RecvDir:
dir = RecvDir
case reflect.SendDir:
dir = SendDir
}
return &ChanType{
Dir: dir,
Type: elemType,
}, nil
case reflect.Func:
in, variadic, out, err := funcArgsFromType(t)
if err != nil {
return nil, err
}
return &FuncType{
In: in,
Out: out,
Variadic: variadic,
}, nil
case reflect.Interface:
// Two special interfaces.
if t.NumMethod() == 0 {
return PredeclaredType("interface{}"), nil
}
if t == errorType {
return PredeclaredType("error"), nil
}
case reflect.Map:
kt, err := typeFromType(t.Key())
if err != nil {
return nil, err
}
return &MapType{
Key: kt,
Value: elemType,
}, nil
case reflect.Ptr:
return &PointerType{
Type: elemType,
}, nil
case reflect.Slice:
return &ArrayType{
Len: -1,
Type: elemType,
}, nil
case reflect.Struct:
if t.NumField() == 0 {
return PredeclaredType("struct{}"), nil
}
}
// TODO: Struct, UnsafePointer
return nil, fmt.Errorf("can't yet turn %v (%v) into a model.Type", t, t.Kind())
}

523
vendor/github.com/golang/mock/mockgen/parse.go generated vendored Normal file
View File

@@ -0,0 +1,523 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
// This file contains the model construction by parsing source files.
import (
"errors"
"flag"
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"log"
"path"
"path/filepath"
"strconv"
"strings"
"github.com/golang/mock/mockgen/model"
"golang.org/x/tools/go/packages"
)
var (
imports = flag.String("imports", "", "(source mode) Comma-separated name=path pairs of explicit imports to use.")
auxFiles = flag.String("aux_files", "", "(source mode) Comma-separated pkg=path pairs of auxiliary Go source files.")
)
// TODO: simplify error reporting
func parseFile(source string) (*model.Package, error) {
srcDir, err := filepath.Abs(filepath.Dir(source))
if err != nil {
return nil, fmt.Errorf("failed getting source directory: %v", err)
}
cfg := &packages.Config{Mode: packages.LoadSyntax, Tests: true}
pkgs, err := packages.Load(cfg, "file="+source)
if err != nil {
return nil, err
}
if packages.PrintErrors(pkgs) > 0 || len(pkgs) == 0 {
return nil, errors.New("loading package failed")
}
packageImport := pkgs[0].PkgPath
// It is illegal to import a _test package.
packageImport = strings.TrimSuffix(packageImport, "_test")
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, source, nil, 0)
if err != nil {
return nil, fmt.Errorf("failed parsing source file %v: %v", source, err)
}
p := &fileParser{
fileSet: fs,
imports: make(map[string]string),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
auxInterfaces: make(map[string]map[string]*ast.InterfaceType),
srcDir: srcDir,
}
// Handle -imports.
dotImports := make(map[string]bool)
if *imports != "" {
for _, kv := range strings.Split(*imports, ",") {
eq := strings.Index(kv, "=")
k, v := kv[:eq], kv[eq+1:]
if k == "." {
// TODO: Catch dupes?
dotImports[v] = true
} else {
// TODO: Catch dupes?
p.imports[k] = v
}
}
}
// Handle -aux_files.
if err := p.parseAuxFiles(*auxFiles); err != nil {
return nil, err
}
p.addAuxInterfacesFromFile(packageImport, file) // this file
pkg, err := p.parseFile(packageImport, file)
if err != nil {
return nil, err
}
for path := range dotImports {
pkg.DotImports = append(pkg.DotImports, path)
}
return pkg, nil
}
type fileParser struct {
fileSet *token.FileSet
imports map[string]string // package name => import path
importedInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface
auxFiles []*ast.File
auxInterfaces map[string]map[string]*ast.InterfaceType // package (or "") => name => interface
srcDir string
}
func (p *fileParser) errorf(pos token.Pos, format string, args ...interface{}) error {
ps := p.fileSet.Position(pos)
format = "%s:%d:%d: " + format
args = append([]interface{}{ps.Filename, ps.Line, ps.Column}, args...)
return fmt.Errorf(format, args...)
}
func (p *fileParser) parseAuxFiles(auxFiles string) error {
auxFiles = strings.TrimSpace(auxFiles)
if auxFiles == "" {
return nil
}
for _, kv := range strings.Split(auxFiles, ",") {
parts := strings.SplitN(kv, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("bad aux file spec: %v", kv)
}
pkg, fpath := parts[0], parts[1]
file, err := parser.ParseFile(p.fileSet, fpath, nil, 0)
if err != nil {
return err
}
p.auxFiles = append(p.auxFiles, file)
p.addAuxInterfacesFromFile(pkg, file)
}
return nil
}
func (p *fileParser) addAuxInterfacesFromFile(pkg string, file *ast.File) {
if _, ok := p.auxInterfaces[pkg]; !ok {
p.auxInterfaces[pkg] = make(map[string]*ast.InterfaceType)
}
for ni := range iterInterfaces(file) {
p.auxInterfaces[pkg][ni.name.Name] = ni.it
}
}
// parseFile loads all file imports and auxiliary files import into the
// fileParser, parses all file interfaces and returns package model.
func (p *fileParser) parseFile(importPath string, file *ast.File) (*model.Package, error) {
allImports, dotImports := importsOfFile(file)
// Don't stomp imports provided by -imports. Those should take precedence.
for pkg, path := range allImports {
if _, ok := p.imports[pkg]; !ok {
p.imports[pkg] = path
}
}
// Add imports from auxiliary files, which might be needed for embedded interfaces.
// Don't stomp any other imports.
for _, f := range p.auxFiles {
auxImports, _ := importsOfFile(f)
for pkg, path := range auxImports {
if _, ok := p.imports[pkg]; !ok {
p.imports[pkg] = path
}
}
}
var is []*model.Interface
for ni := range iterInterfaces(file) {
i, err := p.parseInterface(ni.name.String(), importPath, ni.it)
if err != nil {
return nil, err
}
is = append(is, i)
}
return &model.Package{
Name: file.Name.String(),
Interfaces: is,
DotImports: dotImports,
}, nil
}
// parsePackage loads package specified by path, parses it and populates
// corresponding imports and importedInterfaces into the fileParser.
func (p *fileParser) parsePackage(path string) error {
var pkgs map[string]*ast.Package
if imp, err := build.Import(path, p.srcDir, build.FindOnly); err != nil {
return err
} else if pkgs, err = parser.ParseDir(p.fileSet, imp.Dir, nil, 0); err != nil {
return err
}
for _, pkg := range pkgs {
file := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates|ast.FilterUnassociatedComments|ast.FilterImportDuplicates)
if _, ok := p.importedInterfaces[path]; !ok {
p.importedInterfaces[path] = make(map[string]*ast.InterfaceType)
}
for ni := range iterInterfaces(file) {
p.importedInterfaces[path][ni.name.Name] = ni.it
}
imports, _ := importsOfFile(file)
for pkgName, pkgPath := range imports {
if _, ok := p.imports[pkgName]; !ok {
p.imports[pkgName] = pkgPath
}
}
}
return nil
}
func (p *fileParser) parseInterface(name, pkg string, it *ast.InterfaceType) (*model.Interface, error) {
intf := &model.Interface{Name: name}
for _, field := range it.Methods.List {
switch v := field.Type.(type) {
case *ast.FuncType:
if nn := len(field.Names); nn != 1 {
return nil, fmt.Errorf("expected one name for interface %v, got %d", intf.Name, nn)
}
m := &model.Method{
Name: field.Names[0].String(),
}
var err error
m.In, m.Variadic, m.Out, err = p.parseFunc(pkg, v)
if err != nil {
return nil, err
}
intf.Methods = append(intf.Methods, m)
case *ast.Ident:
// Embedded interface in this package.
ei := p.auxInterfaces[pkg][v.String()]
if ei == nil {
if ei = p.importedInterfaces[pkg][v.String()]; ei == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s", v.String())
}
}
eintf, err := p.parseInterface(v.String(), pkg, ei)
if err != nil {
return nil, err
}
// Copy the methods.
// TODO: apply shadowing rules.
for _, m := range eintf.Methods {
intf.Methods = append(intf.Methods, m)
}
case *ast.SelectorExpr:
// Embedded interface in another package.
fpkg, sel := v.X.(*ast.Ident).String(), v.Sel.String()
epkg, ok := p.imports[fpkg]
if !ok {
return nil, p.errorf(v.X.Pos(), "unknown package %s", fpkg)
}
ei := p.auxInterfaces[fpkg][sel]
if ei == nil {
fpkg = epkg
if _, ok = p.importedInterfaces[epkg]; !ok {
if err := p.parsePackage(epkg); err != nil {
return nil, p.errorf(v.Pos(), "could not parse package %s: %v", fpkg, err)
}
}
if ei = p.importedInterfaces[epkg][sel]; ei == nil {
return nil, p.errorf(v.Pos(), "unknown embedded interface %s.%s", fpkg, sel)
}
}
eintf, err := p.parseInterface(sel, fpkg, ei)
if err != nil {
return nil, err
}
// Copy the methods.
// TODO: apply shadowing rules.
for _, m := range eintf.Methods {
intf.Methods = append(intf.Methods, m)
}
default:
return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type)
}
}
return intf, nil
}
func (p *fileParser) parseFunc(pkg string, f *ast.FuncType) (in []*model.Parameter, variadic *model.Parameter, out []*model.Parameter, err error) {
if f.Params != nil {
regParams := f.Params.List
if isVariadic(f) {
n := len(regParams)
varParams := regParams[n-1:]
regParams = regParams[:n-1]
vp, err := p.parseFieldList(pkg, varParams)
if err != nil {
return nil, nil, nil, p.errorf(varParams[0].Pos(), "failed parsing variadic argument: %v", err)
}
variadic = vp[0]
}
in, err = p.parseFieldList(pkg, regParams)
if err != nil {
return nil, nil, nil, p.errorf(f.Pos(), "failed parsing arguments: %v", err)
}
}
if f.Results != nil {
out, err = p.parseFieldList(pkg, f.Results.List)
if err != nil {
return nil, nil, nil, p.errorf(f.Pos(), "failed parsing returns: %v", err)
}
}
return
}
func (p *fileParser) parseFieldList(pkg string, fields []*ast.Field) ([]*model.Parameter, error) {
nf := 0
for _, f := range fields {
nn := len(f.Names)
if nn == 0 {
nn = 1 // anonymous parameter
}
nf += nn
}
if nf == 0 {
return nil, nil
}
ps := make([]*model.Parameter, nf)
i := 0 // destination index
for _, f := range fields {
t, err := p.parseType(pkg, f.Type)
if err != nil {
return nil, err
}
if len(f.Names) == 0 {
// anonymous arg
ps[i] = &model.Parameter{Type: t}
i++
continue
}
for _, name := range f.Names {
ps[i] = &model.Parameter{Name: name.Name, Type: t}
i++
}
}
return ps, nil
}
func (p *fileParser) parseType(pkg string, typ ast.Expr) (model.Type, error) {
switch v := typ.(type) {
case *ast.ArrayType:
ln := -1
if v.Len != nil {
x, err := strconv.Atoi(v.Len.(*ast.BasicLit).Value)
if err != nil {
return nil, p.errorf(v.Len.Pos(), "bad array size: %v", err)
}
ln = x
}
t, err := p.parseType(pkg, v.Elt)
if err != nil {
return nil, err
}
return &model.ArrayType{Len: ln, Type: t}, nil
case *ast.ChanType:
t, err := p.parseType(pkg, v.Value)
if err != nil {
return nil, err
}
var dir model.ChanDir
if v.Dir == ast.SEND {
dir = model.SendDir
}
if v.Dir == ast.RECV {
dir = model.RecvDir
}
return &model.ChanType{Dir: dir, Type: t}, nil
case *ast.Ellipsis:
// assume we're parsing a variadic argument
return p.parseType(pkg, v.Elt)
case *ast.FuncType:
in, variadic, out, err := p.parseFunc(pkg, v)
if err != nil {
return nil, err
}
return &model.FuncType{In: in, Out: out, Variadic: variadic}, nil
case *ast.Ident:
if v.IsExported() {
// `pkg` may be an aliased imported pkg
// if so, patch the import w/ the fully qualified import
maybeImportedPkg, ok := p.imports[pkg]
if ok {
pkg = maybeImportedPkg
}
// assume type in this package
return &model.NamedType{Package: pkg, Type: v.Name}, nil
}
// assume predeclared type
return model.PredeclaredType(v.Name), nil
case *ast.InterfaceType:
if v.Methods != nil && len(v.Methods.List) > 0 {
return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed interface types")
}
return model.PredeclaredType("interface{}"), nil
case *ast.MapType:
key, err := p.parseType(pkg, v.Key)
if err != nil {
return nil, err
}
value, err := p.parseType(pkg, v.Value)
if err != nil {
return nil, err
}
return &model.MapType{Key: key, Value: value}, nil
case *ast.SelectorExpr:
pkgName := v.X.(*ast.Ident).String()
pkg, ok := p.imports[pkgName]
if !ok {
return nil, p.errorf(v.Pos(), "unknown package %q", pkgName)
}
return &model.NamedType{Package: pkg, Type: v.Sel.String()}, nil
case *ast.StarExpr:
t, err := p.parseType(pkg, v.X)
if err != nil {
return nil, err
}
return &model.PointerType{Type: t}, nil
case *ast.StructType:
if v.Fields != nil && len(v.Fields.List) > 0 {
return nil, p.errorf(v.Pos(), "can't handle non-empty unnamed struct types")
}
return model.PredeclaredType("struct{}"), nil
}
return nil, fmt.Errorf("don't know how to parse type %T", typ)
}
// importsOfFile returns a map of package name to import path
// of the imports in file.
func importsOfFile(file *ast.File) (normalImports map[string]string, dotImports []string) {
normalImports = make(map[string]string)
dotImports = make([]string, 0)
for _, is := range file.Imports {
var pkgName string
importPath := is.Path.Value[1 : len(is.Path.Value)-1] // remove quotes
if is.Name != nil {
// Named imports are always certain.
if is.Name.Name == "_" {
continue
}
pkgName = is.Name.Name
} else {
pkg, err := build.Import(importPath, "", 0)
if err != nil {
// Fallback to import path suffix. Note that this is uncertain.
_, last := path.Split(importPath)
// If the last path component has dots, the first dot-delimited
// field is used as the name.
pkgName = strings.SplitN(last, ".", 2)[0]
} else {
pkgName = pkg.Name
}
}
if pkgName == "." {
dotImports = append(dotImports, importPath)
} else {
if _, ok := normalImports[pkgName]; ok {
log.Fatalf("imported package collision: %q imported twice", pkgName)
}
normalImports[pkgName] = importPath
}
}
return
}
type namedInterface struct {
name *ast.Ident
it *ast.InterfaceType
}
// Create an iterator over all interfaces in file.
func iterInterfaces(file *ast.File) <-chan namedInterface {
ch := make(chan namedInterface)
go func() {
for _, decl := range file.Decls {
gd, ok := decl.(*ast.GenDecl)
if !ok || gd.Tok != token.TYPE {
continue
}
for _, spec := range gd.Specs {
ts, ok := spec.(*ast.TypeSpec)
if !ok {
continue
}
it, ok := ts.Type.(*ast.InterfaceType)
if !ok {
continue
}
ch <- namedInterface{ts.Name, it}
}
}
close(ch)
}()
return ch
}
// isVariadic returns whether the function is variadic.
func isVariadic(f *ast.FuncType) bool {
nargs := len(f.Params.List)
if nargs == 0 {
return false
}
_, ok := f.Params.List[nargs-1].Type.(*ast.Ellipsis)
return ok
}

108
vendor/github.com/golang/mock/mockgen/parse_test.go generated vendored Normal file
View File

@@ -0,0 +1,108 @@
package main
import (
"go/ast"
"go/parser"
"go/token"
"testing"
)
func TestFileParser_ParseFile(t *testing.T) {
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, "internal/tests/custom_package_name/greeter/greeter.go", nil, 0)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
p := fileParser{
fileSet: fs,
imports: make(map[string]string),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
}
pkg, err := p.parseFile("", file)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
checkGreeterImports(t, p.imports)
expectedName := "greeter"
if pkg.Name != expectedName {
t.Fatalf("Expected name to be %v but got %v", expectedName, pkg.Name)
}
expectedInterfaceName := "InputMaker"
if pkg.Interfaces[0].Name != expectedInterfaceName {
t.Fatalf("Expected interface name to be %v but got %v", expectedInterfaceName, pkg.Interfaces[0].Name)
}
}
func TestFileParser_ParsePackage(t *testing.T) {
fs := token.NewFileSet()
_, err := parser.ParseFile(fs, "internal/tests/custom_package_name/greeter/greeter.go", nil, 0)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
p := fileParser{
fileSet: fs,
imports: make(map[string]string),
importedInterfaces: make(map[string]map[string]*ast.InterfaceType),
}
err = p.parsePackage("github.com/golang/mock/mockgen/internal/tests/custom_package_name/greeter")
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
checkGreeterImports(t, p.imports)
}
func TestImportsOfFile(t *testing.T) {
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, "internal/tests/custom_package_name/greeter/greeter.go", nil, 0)
if err != nil {
t.Fatalf("Unexpected error: %v", err)
}
imports, _ := importsOfFile(file)
checkGreeterImports(t, imports)
}
func checkGreeterImports(t *testing.T, imports map[string]string) {
// check that imports have stdlib package "fmt"
if fmtPackage, ok := imports["fmt"]; !ok {
t.Errorf("Expected imports to have key \"fmt\"")
} else {
expectedFmtPackage := "fmt"
if fmtPackage != expectedFmtPackage {
t.Errorf("Expected fmt key to have value %s but got %s", expectedFmtPackage, fmtPackage)
}
}
// check that imports have package named "validator"
if validatorPackage, ok := imports["validator"]; !ok {
t.Errorf("Expected imports to have key \"fmt\"")
} else {
expectedValidatorPackage := "github.com/golang/mock/mockgen/internal/tests/custom_package_name/validator"
if validatorPackage != expectedValidatorPackage {
t.Errorf("Expected validator key to have value %s but got %s", expectedValidatorPackage, validatorPackage)
}
}
// check that imports have package named "client"
if clientPackage, ok := imports["client"]; !ok {
t.Errorf("Expected imports to have key \"client\"")
} else {
expectedClientPackage := "github.com/golang/mock/mockgen/internal/tests/custom_package_name/client/v1"
if clientPackage != expectedClientPackage {
t.Errorf("Expected client key to have value %s but got %s", expectedClientPackage, clientPackage)
}
}
// check that imports don't have package named "v1"
if _, ok := imports["v1"]; ok {
t.Errorf("Expected import not to have key \"v1\"")
}
}

243
vendor/github.com/golang/mock/mockgen/reflect.go generated vendored Normal file
View File

@@ -0,0 +1,243 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
// This file contains the model construction by reflection.
import (
"bytes"
"encoding/gob"
"flag"
"go/build"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"runtime"
"text/template"
"github.com/golang/mock/mockgen/model"
)
var (
progOnly = flag.Bool("prog_only", false, "(reflect mode) Only generate the reflection program; write it to stdout and exit.")
execOnly = flag.String("exec_only", "", "(reflect mode) If set, execute this reflection program.")
buildFlags = flag.String("build_flags", "", "(reflect mode) Additional flags for go build.")
)
func writeProgram(importPath string, symbols []string) ([]byte, error) {
var program bytes.Buffer
data := reflectData{
ImportPath: importPath,
Symbols: symbols,
}
if err := reflectProgram.Execute(&program, &data); err != nil {
return nil, err
}
return program.Bytes(), nil
}
// run the given program and parse the output as a model.Package.
func run(program string) (*model.Package, error) {
f, err := ioutil.TempFile("", "")
if err != nil {
return nil, err
}
filename := f.Name()
defer os.Remove(filename)
if err := f.Close(); err != nil {
return nil, err
}
// Run the program.
cmd := exec.Command(program, "-output", filename)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, err
}
f, err = os.Open(filename)
if err != nil {
return nil, err
}
// Process output.
var pkg model.Package
if err := gob.NewDecoder(f).Decode(&pkg); err != nil {
return nil, err
}
if err := f.Close(); err != nil {
return nil, err
}
return &pkg, nil
}
// runInDir writes the given program into the given dir, runs it there, and
// parses the output as a model.Package.
func runInDir(program []byte, dir string) (*model.Package, error) {
// We use TempDir instead of TempFile so we can control the filename.
tmpDir, err := ioutil.TempDir(dir, "gomock_reflect_")
if err != nil {
return nil, err
}
defer func() {
if err := os.RemoveAll(tmpDir); err != nil {
log.Printf("failed to remove temp directory: %s", err)
}
}()
const progSource = "prog.go"
var progBinary = "prog.bin"
if runtime.GOOS == "windows" {
// Windows won't execute a program unless it has a ".exe" suffix.
progBinary += ".exe"
}
if err := ioutil.WriteFile(filepath.Join(tmpDir, progSource), program, 0600); err != nil {
return nil, err
}
cmdArgs := []string{}
cmdArgs = append(cmdArgs, "build")
if *buildFlags != "" {
cmdArgs = append(cmdArgs, *buildFlags)
}
cmdArgs = append(cmdArgs, "-o", progBinary, progSource)
// Build the program.
cmd := exec.Command("go", cmdArgs...)
cmd.Dir = tmpDir
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, err
}
return run(filepath.Join(tmpDir, progBinary))
}
func reflect(importPath string, symbols []string) (*model.Package, error) {
// TODO: sanity check arguments
if *execOnly != "" {
return run(*execOnly)
}
program, err := writeProgram(importPath, symbols)
if err != nil {
return nil, err
}
if *progOnly {
os.Stdout.Write(program)
os.Exit(0)
}
wd, _ := os.Getwd()
// Try to run the program in the same directory as the input package.
if p, err := build.Import(importPath, wd, build.FindOnly); err == nil {
dir := p.Dir
if p, err := runInDir(program, dir); err == nil {
return p, nil
}
}
// Since that didn't work, try to run it in the current working directory.
if p, err := runInDir(program, wd); err == nil {
return p, nil
}
// Since that didn't work, try to run it in a standard temp directory.
return runInDir(program, "")
}
type reflectData struct {
ImportPath string
Symbols []string
}
// This program reflects on an interface value, and prints the
// gob encoding of a model.Package to standard output.
// JSON doesn't work because of the model.Type interface.
var reflectProgram = template.Must(template.New("program").Parse(`
package main
import (
"encoding/gob"
"flag"
"fmt"
"os"
"path"
"reflect"
"github.com/golang/mock/mockgen/model"
pkg_ {{printf "%q" .ImportPath}}
)
var output = flag.String("output", "", "The output file name, or empty to use stdout.")
func main() {
flag.Parse()
its := []struct{
sym string
typ reflect.Type
}{
{{range .Symbols}}
{ {{printf "%q" .}}, reflect.TypeOf((*pkg_.{{.}})(nil)).Elem()},
{{end}}
}
pkg := &model.Package{
// NOTE: This behaves contrary to documented behaviour if the
// package name is not the final component of the import path.
// The reflect package doesn't expose the package name, though.
Name: path.Base({{printf "%q" .ImportPath}}),
}
for _, it := range its {
intf, err := model.InterfaceFromInterfaceType(it.typ)
if err != nil {
fmt.Fprintf(os.Stderr, "Reflection: %v\n", err)
os.Exit(1)
}
intf.Name = it.sym
pkg.Interfaces = append(pkg.Interfaces, intf)
}
outfile := os.Stdout
if len(*output) != 0 {
var err error
outfile, err = os.Create(*output)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to open output file %q", *output)
}
defer func() {
if err := outfile.Close(); err != nil {
fmt.Fprintf(os.Stderr, "failed to close output file %q", *output)
os.Exit(1)
}
}()
}
if err := gob.NewEncoder(outfile).Encode(pkg); err != nil {
fmt.Fprintf(os.Stderr, "gob encode: %v\n", err)
os.Exit(1)
}
}
`))

View File

@@ -0,0 +1,13 @@
Copyright 2012 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,5 @@
//go:generate mockgen -package empty_interface -destination mock.go -source input.go -copyright_file=LICENSE
package empty_interface
type Empty interface{}

View File

@@ -0,0 +1,46 @@
// Copyright 2012 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Code generated by MockGen. DO NOT EDIT.
// Source: input.go
// Package empty_interface is a generated GoMock package.
package empty_interface
import (
gomock "github.com/golang/mock/gomock"
)
// MockEmpty is a mock of Empty interface
type MockEmpty struct {
ctrl *gomock.Controller
recorder *MockEmptyMockRecorder
}
// MockEmptyMockRecorder is the mock recorder for MockEmpty
type MockEmptyMockRecorder struct {
mock *MockEmpty
}
// NewMockEmpty creates a new mock instance
func NewMockEmpty(ctrl *gomock.Controller) *MockEmpty {
mock := &MockEmpty{ctrl: ctrl}
mock.recorder = &MockEmptyMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockEmpty) EXPECT() *MockEmptyMockRecorder {
return m.recorder
}

16
vendor/github.com/golang/mock/sample/README.md generated vendored Normal file
View File

@@ -0,0 +1,16 @@
This directory contains an example of a package containing a non-trivial
interface that can be mocked with GoMock. The interesting files are:
* `user.go`: Source code for the sample package, containing interfaces to be
mocked. This file depends on the packages named imp[1-4] for various things.
* `user_test.go`: A test for the sample package, in which mocks of the
interfaces from `user.go` are used. This demonstrates how to create mock
objects, set up expectations, and so on.
* `mock_user/mock_user.go`: The generated mock code. See ../gomock/matchers.go
for the `go:generate` command used to generate it.
To run the test,
go test github.com/golang/mock/sample

View File

@@ -0,0 +1,8 @@
//go:generate mockgen -destination mock/concurrent_mock.go github.com/golang/mock/sample/concurrent Math
// Package concurrent demonstrates how to use gomock with goroutines.
package concurrent
type Math interface {
Sum(a, b int) int
}

View File

@@ -0,0 +1,46 @@
package concurrent
import (
"testing"
"context"
"github.com/golang/mock/gomock"
mock "github.com/golang/mock/sample/concurrent/mock"
)
func call(ctx context.Context, m Math) (int, error) {
result := make(chan int)
go func() {
result <- m.Sum(1, 2)
close(result)
}()
select {
case r := <-result:
return r, nil
case <-ctx.Done():
return 0, ctx.Err()
}
}
// testConcurrentFails is expected to fail (and is disabled). It
// demonstrates how to use gomock.WithContext to interrupt the test
// from a different goroutine.
func testConcurrentFails(t *testing.T) {
ctrl, ctx := gomock.WithContext(context.Background(), t)
defer ctrl.Finish()
m := mock.NewMockMath(ctrl)
if _, err := call(ctx, m); err != nil {
t.Error("call failed:", err)
}
}
func TestConcurrentWorks(t *testing.T) {
ctrl, ctx := gomock.WithContext(context.Background(), t)
defer ctrl.Finish()
m := mock.NewMockMath(ctrl)
m.EXPECT().Sum(1, 2).Return(3)
if _, err := call(ctx, m); err != nil {
t.Error("call failed:", err)
}
}

View File

@@ -0,0 +1,47 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/golang/mock/sample/concurrent (interfaces: Math)
// Package mock_concurrent is a generated GoMock package.
package mock_concurrent
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockMath is a mock of Math interface
type MockMath struct {
ctrl *gomock.Controller
recorder *MockMathMockRecorder
}
// MockMathMockRecorder is the mock recorder for MockMath
type MockMathMockRecorder struct {
mock *MockMath
}
// NewMockMath creates a new mock instance
func NewMockMath(ctrl *gomock.Controller) *MockMath {
mock := &MockMath{ctrl: ctrl}
mock.recorder = &MockMathMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockMath) EXPECT() *MockMathMockRecorder {
return m.recorder
}
// Sum mocks base method
func (m *MockMath) Sum(arg0, arg1 int) int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Sum", arg0, arg1)
ret0, _ := ret[0].(int)
return ret0
}
// Sum indicates an expected call of Sum
func (mr *MockMathMockRecorder) Sum(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Sum", reflect.TypeOf((*MockMath)(nil).Sum), arg0, arg1)
}

17
vendor/github.com/golang/mock/sample/imp1/imp1.go generated vendored Normal file
View File

@@ -0,0 +1,17 @@
package imp1
import "bufio"
type Imp1 struct{}
type ImpT int
type ForeignEmbedded interface {
// The return value here also makes sure that
// the generated mock picks up the "bufio" import.
ForeignEmbeddedMethod() *bufio.Reader
// This method uses a type in this package,
// which should be qualified when this interface is embedded.
ImplicitPackage(s string, t ImpT, st []ImpT, pt *ImpT, ct chan ImpT)
}

3
vendor/github.com/golang/mock/sample/imp2/imp2.go generated vendored Normal file
View File

@@ -0,0 +1,3 @@
package imp2
type Imp2 struct{}

3
vendor/github.com/golang/mock/sample/imp3/imp3.go generated vendored Normal file
View File

@@ -0,0 +1,3 @@
package imp3
type Imp3 struct{}

3
vendor/github.com/golang/mock/sample/imp4/imp4.go generated vendored Normal file
View File

@@ -0,0 +1,3 @@
package imp_four
type Imp4 struct{}

View File

@@ -0,0 +1,438 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/golang/mock/sample (interfaces: Index,Embed,Embedded)
// Package mock_sample is a generated GoMock package.
package mock_sample
import (
bufio "bufio"
bytes "bytes"
gomock "github.com/golang/mock/gomock"
imp1 "github.com/golang/mock/sample/imp1"
imp2 "github.com/golang/mock/sample/imp2"
imp3 "github.com/golang/mock/sample/imp3"
imp4 "github.com/golang/mock/sample/imp4"
hash "hash"
template "html/template"
io "io"
http "net/http"
reflect "reflect"
template0 "text/template"
)
// MockIndex is a mock of Index interface
type MockIndex struct {
ctrl *gomock.Controller
recorder *MockIndexMockRecorder
}
// MockIndexMockRecorder is the mock recorder for MockIndex
type MockIndexMockRecorder struct {
mock *MockIndex
}
// NewMockIndex creates a new mock instance
func NewMockIndex(ctrl *gomock.Controller) *MockIndex {
mock := &MockIndex{ctrl: ctrl}
mock.recorder = &MockIndexMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockIndex) EXPECT() *MockIndexMockRecorder {
return m.recorder
}
// Anon mocks base method
func (m *MockIndex) Anon(arg0 string) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Anon", arg0)
}
// Anon indicates an expected call of Anon
func (mr *MockIndexMockRecorder) Anon(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Anon", reflect.TypeOf((*MockIndex)(nil).Anon), arg0)
}
// Chan mocks base method
func (m *MockIndex) Chan(arg0 chan int, arg1 chan<- hash.Hash) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Chan", arg0, arg1)
}
// Chan indicates an expected call of Chan
func (mr *MockIndexMockRecorder) Chan(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Chan", reflect.TypeOf((*MockIndex)(nil).Chan), arg0, arg1)
}
// ConcreteRet mocks base method
func (m *MockIndex) ConcreteRet() chan<- bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ConcreteRet")
ret0, _ := ret[0].(chan<- bool)
return ret0
}
// ConcreteRet indicates an expected call of ConcreteRet
func (mr *MockIndexMockRecorder) ConcreteRet() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConcreteRet", reflect.TypeOf((*MockIndex)(nil).ConcreteRet))
}
// Ellip mocks base method
func (m *MockIndex) Ellip(arg0 string, arg1 ...interface{}) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0}
for _, a := range arg1 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "Ellip", varargs...)
}
// Ellip indicates an expected call of Ellip
func (mr *MockIndexMockRecorder) Ellip(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0}, arg1...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ellip", reflect.TypeOf((*MockIndex)(nil).Ellip), varargs...)
}
// EllipOnly mocks base method
func (m *MockIndex) EllipOnly(arg0 ...string) {
m.ctrl.T.Helper()
varargs := []interface{}{}
for _, a := range arg0 {
varargs = append(varargs, a)
}
m.ctrl.Call(m, "EllipOnly", varargs...)
}
// EllipOnly indicates an expected call of EllipOnly
func (mr *MockIndexMockRecorder) EllipOnly(arg0 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EllipOnly", reflect.TypeOf((*MockIndex)(nil).EllipOnly), arg0...)
}
// ForeignFour mocks base method
func (m *MockIndex) ForeignFour(arg0 imp4.Imp4) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ForeignFour", arg0)
}
// ForeignFour indicates an expected call of ForeignFour
func (mr *MockIndexMockRecorder) ForeignFour(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignFour", reflect.TypeOf((*MockIndex)(nil).ForeignFour), arg0)
}
// ForeignOne mocks base method
func (m *MockIndex) ForeignOne(arg0 imp1.Imp1) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ForeignOne", arg0)
}
// ForeignOne indicates an expected call of ForeignOne
func (mr *MockIndexMockRecorder) ForeignOne(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignOne", reflect.TypeOf((*MockIndex)(nil).ForeignOne), arg0)
}
// ForeignThree mocks base method
func (m *MockIndex) ForeignThree(arg0 imp3.Imp3) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ForeignThree", arg0)
}
// ForeignThree indicates an expected call of ForeignThree
func (mr *MockIndexMockRecorder) ForeignThree(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignThree", reflect.TypeOf((*MockIndex)(nil).ForeignThree), arg0)
}
// ForeignTwo mocks base method
func (m *MockIndex) ForeignTwo(arg0 imp2.Imp2) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ForeignTwo", arg0)
}
// ForeignTwo indicates an expected call of ForeignTwo
func (mr *MockIndexMockRecorder) ForeignTwo(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignTwo", reflect.TypeOf((*MockIndex)(nil).ForeignTwo), arg0)
}
// Func mocks base method
func (m *MockIndex) Func(arg0 func(http.Request) (int, bool)) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Func", arg0)
}
// Func indicates an expected call of Func
func (mr *MockIndexMockRecorder) Func(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Func", reflect.TypeOf((*MockIndex)(nil).Func), arg0)
}
// Get mocks base method
func (m *MockIndex) Get(arg0 string) interface{} {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Get", arg0)
ret0, _ := ret[0].(interface{})
return ret0
}
// Get indicates an expected call of Get
func (mr *MockIndexMockRecorder) Get(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Get", reflect.TypeOf((*MockIndex)(nil).Get), arg0)
}
// GetTwo mocks base method
func (m *MockIndex) GetTwo(arg0, arg1 string) (interface{}, interface{}) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTwo", arg0, arg1)
ret0, _ := ret[0].(interface{})
ret1, _ := ret[1].(interface{})
return ret0, ret1
}
// GetTwo indicates an expected call of GetTwo
func (mr *MockIndexMockRecorder) GetTwo(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTwo", reflect.TypeOf((*MockIndex)(nil).GetTwo), arg0, arg1)
}
// Map mocks base method
func (m *MockIndex) Map(arg0 map[int]hash.Hash) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Map", arg0)
}
// Map indicates an expected call of Map
func (mr *MockIndexMockRecorder) Map(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Map", reflect.TypeOf((*MockIndex)(nil).Map), arg0)
}
// NillableRet mocks base method
func (m *MockIndex) NillableRet() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "NillableRet")
ret0, _ := ret[0].(error)
return ret0
}
// NillableRet indicates an expected call of NillableRet
func (mr *MockIndexMockRecorder) NillableRet() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NillableRet", reflect.TypeOf((*MockIndex)(nil).NillableRet))
}
// Other mocks base method
func (m *MockIndex) Other() hash.Hash {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Other")
ret0, _ := ret[0].(hash.Hash)
return ret0
}
// Other indicates an expected call of Other
func (mr *MockIndexMockRecorder) Other() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Other", reflect.TypeOf((*MockIndex)(nil).Other))
}
// Ptr mocks base method
func (m *MockIndex) Ptr(arg0 *int) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Ptr", arg0)
}
// Ptr indicates an expected call of Ptr
func (mr *MockIndexMockRecorder) Ptr(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Ptr", reflect.TypeOf((*MockIndex)(nil).Ptr), arg0)
}
// Put mocks base method
func (m *MockIndex) Put(arg0 string, arg1 interface{}) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Put", arg0, arg1)
}
// Put indicates an expected call of Put
func (mr *MockIndexMockRecorder) Put(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockIndex)(nil).Put), arg0, arg1)
}
// Slice mocks base method
func (m *MockIndex) Slice(arg0 []int, arg1 []byte) [3]int {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Slice", arg0, arg1)
ret0, _ := ret[0].([3]int)
return ret0
}
// Slice indicates an expected call of Slice
func (mr *MockIndexMockRecorder) Slice(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Slice", reflect.TypeOf((*MockIndex)(nil).Slice), arg0, arg1)
}
// Struct mocks base method
func (m *MockIndex) Struct(arg0 struct{}) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Struct", arg0)
}
// Struct indicates an expected call of Struct
func (mr *MockIndexMockRecorder) Struct(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Struct", reflect.TypeOf((*MockIndex)(nil).Struct), arg0)
}
// StructChan mocks base method
func (m *MockIndex) StructChan(arg0 chan struct{}) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "StructChan", arg0)
}
// StructChan indicates an expected call of StructChan
func (mr *MockIndexMockRecorder) StructChan(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StructChan", reflect.TypeOf((*MockIndex)(nil).StructChan), arg0)
}
// Summary mocks base method
func (m *MockIndex) Summary(arg0 *bytes.Buffer, arg1 io.Writer) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Summary", arg0, arg1)
}
// Summary indicates an expected call of Summary
func (mr *MockIndexMockRecorder) Summary(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Summary", reflect.TypeOf((*MockIndex)(nil).Summary), arg0, arg1)
}
// Templates mocks base method
func (m *MockIndex) Templates(arg0 template.CSS, arg1 template0.FuncMap) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "Templates", arg0, arg1)
}
// Templates indicates an expected call of Templates
func (mr *MockIndexMockRecorder) Templates(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Templates", reflect.TypeOf((*MockIndex)(nil).Templates), arg0, arg1)
}
// MockEmbed is a mock of Embed interface
type MockEmbed struct {
ctrl *gomock.Controller
recorder *MockEmbedMockRecorder
}
// MockEmbedMockRecorder is the mock recorder for MockEmbed
type MockEmbedMockRecorder struct {
mock *MockEmbed
}
// NewMockEmbed creates a new mock instance
func NewMockEmbed(ctrl *gomock.Controller) *MockEmbed {
mock := &MockEmbed{ctrl: ctrl}
mock.recorder = &MockEmbedMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockEmbed) EXPECT() *MockEmbedMockRecorder {
return m.recorder
}
// EmbeddedMethod mocks base method
func (m *MockEmbed) EmbeddedMethod() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "EmbeddedMethod")
}
// EmbeddedMethod indicates an expected call of EmbeddedMethod
func (mr *MockEmbedMockRecorder) EmbeddedMethod() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedMethod", reflect.TypeOf((*MockEmbed)(nil).EmbeddedMethod))
}
// ForeignEmbeddedMethod mocks base method
func (m *MockEmbed) ForeignEmbeddedMethod() *bufio.Reader {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ForeignEmbeddedMethod")
ret0, _ := ret[0].(*bufio.Reader)
return ret0
}
// ForeignEmbeddedMethod indicates an expected call of ForeignEmbeddedMethod
func (mr *MockEmbedMockRecorder) ForeignEmbeddedMethod() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ForeignEmbeddedMethod", reflect.TypeOf((*MockEmbed)(nil).ForeignEmbeddedMethod))
}
// ImplicitPackage mocks base method
func (m *MockEmbed) ImplicitPackage(arg0 string, arg1 imp1.ImpT, arg2 []imp1.ImpT, arg3 *imp1.ImpT, arg4 chan imp1.ImpT) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ImplicitPackage", arg0, arg1, arg2, arg3, arg4)
}
// ImplicitPackage indicates an expected call of ImplicitPackage
func (mr *MockEmbedMockRecorder) ImplicitPackage(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ImplicitPackage", reflect.TypeOf((*MockEmbed)(nil).ImplicitPackage), arg0, arg1, arg2, arg3, arg4)
}
// RegularMethod mocks base method
func (m *MockEmbed) RegularMethod() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "RegularMethod")
}
// RegularMethod indicates an expected call of RegularMethod
func (mr *MockEmbedMockRecorder) RegularMethod() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RegularMethod", reflect.TypeOf((*MockEmbed)(nil).RegularMethod))
}
// MockEmbedded is a mock of Embedded interface
type MockEmbedded struct {
ctrl *gomock.Controller
recorder *MockEmbeddedMockRecorder
}
// MockEmbeddedMockRecorder is the mock recorder for MockEmbedded
type MockEmbeddedMockRecorder struct {
mock *MockEmbedded
}
// NewMockEmbedded creates a new mock instance
func NewMockEmbedded(ctrl *gomock.Controller) *MockEmbedded {
mock := &MockEmbedded{ctrl: ctrl}
mock.recorder = &MockEmbeddedMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockEmbedded) EXPECT() *MockEmbeddedMockRecorder {
return m.recorder
}
// EmbeddedMethod mocks base method
func (m *MockEmbedded) EmbeddedMethod() {
m.ctrl.T.Helper()
m.ctrl.Call(m, "EmbeddedMethod")
}
// EmbeddedMethod indicates an expected call of EmbeddedMethod
func (mr *MockEmbeddedMockRecorder) EmbeddedMethod() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EmbeddedMethod", reflect.TypeOf((*MockEmbedded)(nil).EmbeddedMethod))
}

114
vendor/github.com/golang/mock/sample/user.go generated vendored Normal file
View File

@@ -0,0 +1,114 @@
//go:generate mockgen -destination mock_user/mock_user.go github.com/golang/mock/sample Index,Embed,Embedded
// An example package with an interface.
package user
// Random bunch of imports to test mockgen.
import "io"
import (
btz "bytes"
"hash"
"log"
"net"
"net/http"
// Two imports with the same base name.
t1 "html/template"
t2 "text/template"
)
// Dependencies outside the standard library.
import (
"github.com/golang/mock/sample/imp1"
renamed2 "github.com/golang/mock/sample/imp2"
. "github.com/golang/mock/sample/imp3"
"github.com/golang/mock/sample/imp4" // calls itself "imp_four"
)
// A bizarre interface to test corner cases in mockgen.
// This would normally be in its own file or package,
// separate from the user of it (e.g. io.Reader).
type Index interface {
Get(key string) interface{}
GetTwo(key1, key2 string) (v1, v2 interface{})
Put(key string, value interface{})
// Check that imports are handled correctly.
Summary(buf *btz.Buffer, w io.Writer)
Other() hash.Hash
Templates(a t1.CSS, b t2.FuncMap)
// A method with an anonymous argument.
Anon(string)
// Methods using foreign types outside the standard library.
ForeignOne(imp1.Imp1)
ForeignTwo(renamed2.Imp2)
ForeignThree(Imp3)
ForeignFour(imp_four.Imp4)
// A method that returns a nillable type.
NillableRet() error
// A method that returns a non-interface type.
ConcreteRet() chan<- bool
// Methods with an ellipsis argument.
Ellip(fmt string, args ...interface{})
EllipOnly(...string)
// A method with a pointer argument that we will set.
Ptr(arg *int)
// A method with a slice argument and an array return.
Slice(a []int, b []byte) [3]int
// A method with channel arguments.
Chan(a chan int, b chan<- hash.Hash)
// A method with a function argument.
Func(f func(http.Request) (int, bool))
// A method with a map argument.
Map(a map[int]hash.Hash)
// Methods with an unnamed empty struct argument.
Struct(a struct{}) // not so likely
StructChan(a chan struct{}) // a bit more common
}
// An interface with an embedded interface.
type Embed interface {
RegularMethod()
Embedded
imp1.ForeignEmbedded
}
type Embedded interface {
EmbeddedMethod()
}
// some random use of another package that isn't needed by the interface.
var _ net.Addr
// A function that we will test that uses the above interface.
// It takes a list of keys and values, and puts them in the index.
func Remember(index Index, keys []string, values []interface{}) {
for i, k := range keys {
index.Put(k, values[i])
}
err := index.NillableRet()
if err != nil {
log.Fatalf("Woah! %v", err)
}
if len(keys) > 0 && keys[0] == "a" {
index.Ellip("%d", 0, 1, 1, 2, 3)
index.Ellip("%d", 1, 3, 6, 10, 15)
index.EllipOnly("arg")
}
}
func GrabPointer(index Index) int {
var a int
index.Ptr(&a)
return a
}

161
vendor/github.com/golang/mock/sample/user_test.go generated vendored Normal file
View File

@@ -0,0 +1,161 @@
// A test that uses a mock.
package user_test
import (
"testing"
"github.com/golang/mock/gomock"
"github.com/golang/mock/sample"
"github.com/golang/mock/sample/imp1"
mock_user "github.com/golang/mock/sample/mock_user"
)
func TestRemember(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex.EXPECT().Put("a", 1) // literals work
mockIndex.EXPECT().Put("b", gomock.Eq(2)) // matchers work too
// NillableRet returns error. Not declaring it should result in a nil return.
mockIndex.EXPECT().NillableRet()
// Calls that returns something assignable to the return type.
boolc := make(chan bool)
// In this case, "chan bool" is assignable to "chan<- bool".
mockIndex.EXPECT().ConcreteRet().Return(boolc)
// In this case, nil is assignable to "chan<- bool".
mockIndex.EXPECT().ConcreteRet().Return(nil)
// Should be able to place expectations on variadic methods.
mockIndex.EXPECT().Ellip("%d", 0, 1, 1, 2, 3) // direct args
tri := []interface{}{1, 3, 6, 10, 15}
mockIndex.EXPECT().Ellip("%d", tri...) // args from slice
mockIndex.EXPECT().EllipOnly(gomock.Eq("arg"))
user.Remember(mockIndex, []string{"a", "b"}, []interface{}{1, 2})
// Check the ConcreteRet calls.
if c := mockIndex.ConcreteRet(); c != boolc {
t.Errorf("ConcreteRet: got %v, want %v", c, boolc)
}
if c := mockIndex.ConcreteRet(); c != nil {
t.Errorf("ConcreteRet: got %v, want nil", c)
}
// Try one with an action.
calledString := ""
mockIndex.EXPECT().Put(gomock.Any(), gomock.Any()).Do(func(key string, _ interface{}) {
calledString = key
})
mockIndex.EXPECT().NillableRet()
user.Remember(mockIndex, []string{"blah"}, []interface{}{7})
if calledString != "blah" {
t.Fatalf(`Uh oh. %q != "blah"`, calledString)
}
// Use Do with a nil arg.
mockIndex.EXPECT().Put("nil-key", gomock.Any()).Do(func(key string, value interface{}) {
if value != nil {
t.Errorf("Put did not pass through nil; got %v", value)
}
})
mockIndex.EXPECT().NillableRet()
user.Remember(mockIndex, []string{"nil-key"}, []interface{}{nil})
}
func TestVariadicFunction(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex.EXPECT().Ellip("%d", 5, 6, 7, 8).Do(func(format string, nums ...int) {
sum := 0
for _, value := range nums {
sum += value
}
if sum != 26 {
t.Errorf("Expected 7, got %d", sum)
}
})
mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
sum := 0
for _, value := range nums {
sum += value
}
if sum != 10 {
t.Errorf("Expected 7, got %d", sum)
}
})
mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
sum := 0
for _, value := range nums {
sum += value
}
if sum != 0 {
t.Errorf("Expected 0, got %d", sum)
}
})
mockIndex.EXPECT().Ellip("%d", gomock.Any()).Do(func(format string, nums ...int) {
sum := 0
for _, value := range nums {
sum += value
}
if sum != 0 {
t.Errorf("Expected 0, got %d", sum)
}
})
mockIndex.EXPECT().Ellip("%d").Do(func(format string, nums ...int) {
sum := 0
for _, value := range nums {
sum += value
}
if sum != 0 {
t.Errorf("Expected 0, got %d", sum)
}
})
mockIndex.Ellip("%d", 1, 2, 3, 4) // Match second matcher.
mockIndex.Ellip("%d", 5, 6, 7, 8) // Match first matcher.
mockIndex.Ellip("%d", 0)
mockIndex.Ellip("%d")
mockIndex.Ellip("%d")
}
func TestGrabPointer(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex.EXPECT().Ptr(gomock.Any()).SetArg(0, 7) // set first argument to 7
i := user.GrabPointer(mockIndex)
if i != 7 {
t.Errorf("Expected 7, got %d", i)
}
}
func TestEmbeddedInterface(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockEmbed := mock_user.NewMockEmbed(ctrl)
mockEmbed.EXPECT().RegularMethod()
mockEmbed.EXPECT().EmbeddedMethod()
mockEmbed.EXPECT().ForeignEmbeddedMethod()
mockEmbed.RegularMethod()
mockEmbed.EmbeddedMethod()
var emb imp1.ForeignEmbedded = mockEmbed // also does interface check
emb.ForeignEmbeddedMethod()
}
func TestExpectTrueNil(t *testing.T) {
// Make sure that passing "nil" to EXPECT (thus as a nil interface value),
// will correctly match a nil concrete type.
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockIndex := mock_user.NewMockIndex(ctrl)
mockIndex.EXPECT().Ptr(nil) // this nil is a nil interface{}
mockIndex.Ptr(nil) // this nil is a nil *int
}

View File

@@ -0,0 +1,3 @@
# This source code refers to The Go Authors for copyright purposes.
# The master list of authors is in the main Go distribution,
# visible at http://tip.golang.org/AUTHORS.

View File

@@ -0,0 +1,3 @@
# This source code was written by the Go contributors.
# The master list of contributors is in the main Go distribution,
# visible at http://tip.golang.org/CONTRIBUTORS.

View File

@@ -0,0 +1,27 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,22 @@
Additional IP Rights Grant (Patents)
"This implementation" means the copyrightable works distributed by
Google as part of the Go project.
Google hereby grants to You a perpetual, worldwide, non-exclusive,
no-charge, royalty-free, irrevocable (except as stated in this section)
patent license to make, have made, use, offer to sell, sell, import,
transfer and otherwise run, modify and propagate the contents of this
implementation of Go, where such license applies only to those patent
claims, both currently owned or controlled by Google and acquired in
the future, licensable by Google that are necessarily infringed by this
implementation of Go. This grant does not include claims that would be
infringed only as a consequence of further modification of this
implementation. If you or your agent or exclusive licensee institute or
order or agree to the institution of patent litigation against any
entity (including a cross-claim or counterclaim in a lawsuit) alleging
that this implementation of Go or any code incorporated within this
implementation of Go constitutes direct or contributory patent
infringement, or inducement of patent infringement, then any patent
rights granted to you under this License for this implementation of Go
shall terminate as of the date such litigation is filed.

View File

@@ -0,0 +1,109 @@
// Copyright 2016 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 gcexportdata provides functions for locating, reading, and
// writing export data files containing type information produced by the
// gc compiler. This package supports go1.7 export data format and all
// later versions.
//
// Although it might seem convenient for this package to live alongside
// go/types in the standard library, this would cause version skew
// problems for developer tools that use it, since they must be able to
// consume the outputs of the gc compiler both before and after a Go
// update such as from Go 1.7 to Go 1.8. Because this package lives in
// golang.org/x/tools, sites can update their version of this repo some
// time before the Go 1.8 release and rebuild and redeploy their
// developer tools, which will then be able to consume both Go 1.7 and
// Go 1.8 export data files, so they will work before and after the
// Go update. (See discussion at https://golang.org/issue/15651.)
//
package gcexportdata // import "golang.org/x/tools/go/gcexportdata"
import (
"bufio"
"bytes"
"fmt"
"go/token"
"go/types"
"io"
"io/ioutil"
"golang.org/x/tools/go/internal/gcimporter"
)
// Find returns the name of an object (.o) or archive (.a) file
// containing type information for the specified import path,
// using the workspace layout conventions of go/build.
// If no file was found, an empty filename is returned.
//
// A relative srcDir is interpreted relative to the current working directory.
//
// Find also returns the package's resolved (canonical) import path,
// reflecting the effects of srcDir and vendoring on importPath.
func Find(importPath, srcDir string) (filename, path string) {
return gcimporter.FindPkg(importPath, srcDir)
}
// NewReader returns a reader for the export data section of an object
// (.o) or archive (.a) file read from r. The new reader may provide
// additional trailing data beyond the end of the export data.
func NewReader(r io.Reader) (io.Reader, error) {
buf := bufio.NewReader(r)
_, err := gcimporter.FindExportData(buf)
// If we ever switch to a zip-like archive format with the ToC
// at the end, we can return the correct portion of export data,
// but for now we must return the entire rest of the file.
return buf, err
}
// Read reads export data from in, decodes it, and returns type
// information for the package.
// The package name is specified by path.
// File position information is added to fset.
//
// Read may inspect and add to the imports map to ensure that references
// within the export data to other packages are consistent. The caller
// must ensure that imports[path] does not exist, or exists but is
// incomplete (see types.Package.Complete), and Read inserts the
// resulting package into this map entry.
//
// On return, the state of the reader is undefined.
func Read(in io.Reader, fset *token.FileSet, imports map[string]*types.Package, path string) (*types.Package, error) {
data, err := ioutil.ReadAll(in)
if err != nil {
return nil, fmt.Errorf("reading export data for %q: %v", path, err)
}
if bytes.HasPrefix(data, []byte("!<arch>")) {
return nil, fmt.Errorf("can't read export data for %q directly from an archive file (call gcexportdata.NewReader first to extract export data)", path)
}
// The App Engine Go runtime v1.6 uses the old export data format.
// TODO(adonovan): delete once v1.7 has been around for a while.
if bytes.HasPrefix(data, []byte("package ")) {
return gcimporter.ImportData(imports, path, path, bytes.NewReader(data))
}
// The indexed export format starts with an 'i'; the older
// binary export format starts with a 'c', 'd', or 'v'
// (from "version"). Select appropriate importer.
if len(data) > 0 && data[0] == 'i' {
_, pkg, err := gcimporter.IImportData(fset, imports, data[1:], path)
return pkg, err
}
_, pkg, err := gcimporter.BImportData(fset, imports, data, path)
return pkg, err
}
// Write writes encoded type information for the specified package to out.
// The FileSet provides file position information for named objects.
func Write(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
b, err := gcimporter.BExportData(fset, pkg)
if err != nil {
return err
}
_, err = out.Write(b)
return err
}

View File

@@ -0,0 +1,73 @@
// Copyright 2016 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 gcexportdata
import (
"fmt"
"go/token"
"go/types"
"os"
)
// NewImporter returns a new instance of the types.Importer interface
// that reads type information from export data files written by gc.
// The Importer also satisfies types.ImporterFrom.
//
// Export data files are located using "go build" workspace conventions
// and the build.Default context.
//
// Use this importer instead of go/importer.For("gc", ...) to avoid the
// version-skew problems described in the documentation of this package,
// or to control the FileSet or access the imports map populated during
// package loading.
//
func NewImporter(fset *token.FileSet, imports map[string]*types.Package) types.ImporterFrom {
return importer{fset, imports}
}
type importer struct {
fset *token.FileSet
imports map[string]*types.Package
}
func (imp importer) Import(importPath string) (*types.Package, error) {
return imp.ImportFrom(importPath, "", 0)
}
func (imp importer) ImportFrom(importPath, srcDir string, mode types.ImportMode) (_ *types.Package, err error) {
filename, path := Find(importPath, srcDir)
if filename == "" {
if importPath == "unsafe" {
// Even for unsafe, call Find first in case
// the package was vendored.
return types.Unsafe, nil
}
return nil, fmt.Errorf("can't find import: %s", importPath)
}
if pkg, ok := imp.imports[path]; ok && pkg.Complete() {
return pkg, nil // cache hit
}
// open file
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer func() {
f.Close()
if err != nil {
// add file name to error
err = fmt.Errorf("reading export data: %s: %v", filename, err)
}
}()
r, err := NewReader(f)
if err != nil {
return nil, err
}
return Read(r, imp.fset, imp.imports, path)
}

View File

@@ -0,0 +1,99 @@
// Copyright 2017 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.
// +build ignore
// The gcexportdata command is a diagnostic tool that displays the
// contents of gc export data files.
package main
import (
"flag"
"fmt"
"go/token"
"go/types"
"log"
"os"
"golang.org/x/tools/go/gcexportdata"
"golang.org/x/tools/go/types/typeutil"
)
var packageFlag = flag.String("package", "", "alternative package to print")
func main() {
log.SetPrefix("gcexportdata: ")
log.SetFlags(0)
flag.Usage = func() {
fmt.Fprintln(os.Stderr, "usage: gcexportdata [-package path] file.a")
}
flag.Parse()
if flag.NArg() != 1 {
flag.Usage()
os.Exit(2)
}
filename := flag.Args()[0]
f, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
r, err := gcexportdata.NewReader(f)
if err != nil {
log.Fatalf("%s: %s", filename, err)
}
// Decode the package.
const primary = "<primary>"
imports := make(map[string]*types.Package)
fset := token.NewFileSet()
pkg, err := gcexportdata.Read(r, fset, imports, primary)
if err != nil {
log.Fatalf("%s: %s", filename, err)
}
// Optionally select an indirectly mentioned package.
if *packageFlag != "" {
pkg = imports[*packageFlag]
if pkg == nil {
fmt.Fprintf(os.Stderr, "export data file %s does not mention %s; has:\n",
filename, *packageFlag)
for p := range imports {
if p != primary {
fmt.Fprintf(os.Stderr, "\t%s\n", p)
}
}
os.Exit(1)
}
}
// Print all package-level declarations, including non-exported ones.
fmt.Printf("package %s\n", pkg.Name())
for _, imp := range pkg.Imports() {
fmt.Printf("import %q\n", imp.Path())
}
qual := func(p *types.Package) string {
if pkg == p {
return ""
}
return p.Name()
}
scope := pkg.Scope()
for _, name := range scope.Names() {
obj := scope.Lookup(name)
fmt.Printf("%s: %s\n",
fset.Position(obj.Pos()),
types.ObjectString(obj, qual))
// For types, print each method.
if _, ok := obj.(*types.TypeName); ok {
for _, method := range typeutil.IntuitiveMethodSet(obj.Type(), nil) {
fmt.Printf("%s: %s\n",
fset.Position(method.Obj().Pos()),
types.SelectionString(method, qual))
}
}
}
}

View File

@@ -0,0 +1,220 @@
// 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 cgo
// This file handles cgo preprocessing of files containing `import "C"`.
//
// DESIGN
//
// The approach taken is to run the cgo processor on the package's
// CgoFiles and parse the output, faking the filenames of the
// resulting ASTs so that the synthetic file containing the C types is
// called "C" (e.g. "~/go/src/net/C") and the preprocessed files
// have their original names (e.g. "~/go/src/net/cgo_unix.go"),
// not the names of the actual temporary files.
//
// The advantage of this approach is its fidelity to 'go build'. The
// downside is that the token.Position.Offset for each AST node is
// incorrect, being an offset within the temporary file. Line numbers
// should still be correct because of the //line comments.
//
// The logic of this file is mostly plundered from the 'go build'
// tool, which also invokes the cgo preprocessor.
//
//
// REJECTED ALTERNATIVE
//
// An alternative approach that we explored is to extend go/types'
// Importer mechanism to provide the identity of the importing package
// so that each time `import "C"` appears it resolves to a different
// synthetic package containing just the objects needed in that case.
// The loader would invoke cgo but parse only the cgo_types.go file
// defining the package-level objects, discarding the other files
// resulting from preprocessing.
//
// The benefit of this approach would have been that source-level
// syntax information would correspond exactly to the original cgo
// file, with no preprocessing involved, making source tools like
// godoc, guru, and eg happy. However, the approach was rejected
// due to the additional complexity it would impose on go/types. (It
// made for a beautiful demo, though.)
//
// cgo files, despite their *.go extension, are not legal Go source
// files per the specification since they may refer to unexported
// members of package "C" such as C.int. Also, a function such as
// C.getpwent has in effect two types, one matching its C type and one
// which additionally returns (errno C.int). The cgo preprocessor
// uses name mangling to distinguish these two functions in the
// processed code, but go/types would need to duplicate this logic in
// its handling of function calls, analogous to the treatment of map
// lookups in which y=m[k] and y,ok=m[k] are both legal.
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
)
// ProcessFiles invokes the cgo preprocessor on bp.CgoFiles, parses
// the output and returns the resulting ASTs.
//
func ProcessFiles(bp *build.Package, fset *token.FileSet, DisplayPath func(path string) string, mode parser.Mode) ([]*ast.File, error) {
tmpdir, err := ioutil.TempDir("", strings.Replace(bp.ImportPath, "/", "_", -1)+"_C")
if err != nil {
return nil, err
}
defer os.RemoveAll(tmpdir)
pkgdir := bp.Dir
if DisplayPath != nil {
pkgdir = DisplayPath(pkgdir)
}
cgoFiles, cgoDisplayFiles, err := Run(bp, pkgdir, tmpdir, false)
if err != nil {
return nil, err
}
var files []*ast.File
for i := range cgoFiles {
rd, err := os.Open(cgoFiles[i])
if err != nil {
return nil, err
}
display := filepath.Join(bp.Dir, cgoDisplayFiles[i])
f, err := parser.ParseFile(fset, display, rd, mode)
rd.Close()
if err != nil {
return nil, err
}
files = append(files, f)
}
return files, nil
}
var cgoRe = regexp.MustCompile(`[/\\:]`)
// Run invokes the cgo preprocessor on bp.CgoFiles and returns two
// lists of files: the resulting processed files (in temporary
// directory tmpdir) and the corresponding names of the unprocessed files.
//
// Run is adapted from (*builder).cgo in
// $GOROOT/src/cmd/go/build.go, but these features are unsupported:
// Objective C, CGOPKGPATH, CGO_FLAGS.
//
// If useabs is set to true, absolute paths of the bp.CgoFiles will be passed in
// to the cgo preprocessor. This in turn will set the // line comments
// referring to those files to use absolute paths. This is needed for
// go/packages using the legacy go list support so it is able to find
// the original files.
func Run(bp *build.Package, pkgdir, tmpdir string, useabs bool) (files, displayFiles []string, err error) {
cgoCPPFLAGS, _, _, _ := cflags(bp, true)
_, cgoexeCFLAGS, _, _ := cflags(bp, false)
if len(bp.CgoPkgConfig) > 0 {
pcCFLAGS, err := pkgConfigFlags(bp)
if err != nil {
return nil, nil, err
}
cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
}
// Allows including _cgo_export.h from .[ch] files in the package.
cgoCPPFLAGS = append(cgoCPPFLAGS, "-I", tmpdir)
// _cgo_gotypes.go (displayed "C") contains the type definitions.
files = append(files, filepath.Join(tmpdir, "_cgo_gotypes.go"))
displayFiles = append(displayFiles, "C")
for _, fn := range bp.CgoFiles {
// "foo.cgo1.go" (displayed "foo.go") is the processed Go source.
f := cgoRe.ReplaceAllString(fn[:len(fn)-len("go")], "_")
files = append(files, filepath.Join(tmpdir, f+"cgo1.go"))
displayFiles = append(displayFiles, fn)
}
var cgoflags []string
if bp.Goroot && bp.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_runtime_cgo=false")
}
if bp.Goroot && bp.ImportPath == "runtime/race" || bp.ImportPath == "runtime/cgo" {
cgoflags = append(cgoflags, "-import_syscall=false")
}
var cgoFiles []string = bp.CgoFiles
if useabs {
cgoFiles = make([]string, len(bp.CgoFiles))
for i := range cgoFiles {
cgoFiles[i] = filepath.Join(pkgdir, bp.CgoFiles[i])
}
}
args := stringList(
"go", "tool", "cgo", "-objdir", tmpdir, cgoflags, "--",
cgoCPPFLAGS, cgoexeCFLAGS, cgoFiles,
)
if false {
log.Printf("Running cgo for package %q: %s (dir=%s)", bp.ImportPath, args, pkgdir)
}
cmd := exec.Command(args[0], args[1:]...)
cmd.Dir = pkgdir
cmd.Stdout = os.Stderr
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
return nil, nil, fmt.Errorf("cgo failed: %s: %s", args, err)
}
return files, displayFiles, nil
}
// -- unmodified from 'go build' ---------------------------------------
// Return the flags to use when invoking the C or C++ compilers, or cgo.
func cflags(p *build.Package, def bool) (cppflags, cflags, cxxflags, ldflags []string) {
var defaults string
if def {
defaults = "-g -O2"
}
cppflags = stringList(envList("CGO_CPPFLAGS", ""), p.CgoCPPFLAGS)
cflags = stringList(envList("CGO_CFLAGS", defaults), p.CgoCFLAGS)
cxxflags = stringList(envList("CGO_CXXFLAGS", defaults), p.CgoCXXFLAGS)
ldflags = stringList(envList("CGO_LDFLAGS", defaults), p.CgoLDFLAGS)
return
}
// envList returns the value of the given environment variable broken
// into fields, using the default value when the variable is empty.
func envList(key, def string) []string {
v := os.Getenv(key)
if v == "" {
v = def
}
return strings.Fields(v)
}
// stringList's arguments should be a sequence of string or []string values.
// stringList flattens them into a single []string.
func stringList(args ...interface{}) []string {
var x []string
for _, arg := range args {
switch arg := arg.(type) {
case []string:
x = append(x, arg...)
case string:
x = append(x, arg)
default:
panic("stringList: invalid argument")
}
}
return x
}

View File

@@ -0,0 +1,39 @@
// 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 cgo
import (
"errors"
"fmt"
"go/build"
"os/exec"
"strings"
)
// pkgConfig runs pkg-config with the specified arguments and returns the flags it prints.
func pkgConfig(mode string, pkgs []string) (flags []string, err error) {
cmd := exec.Command("pkg-config", append([]string{mode}, pkgs...)...)
out, err := cmd.CombinedOutput()
if err != nil {
s := fmt.Sprintf("%s failed: %v", strings.Join(cmd.Args, " "), err)
if len(out) > 0 {
s = fmt.Sprintf("%s: %s", s, out)
}
return nil, errors.New(s)
}
if len(out) > 0 {
flags = strings.Fields(string(out))
}
return
}
// pkgConfigFlags calls pkg-config if needed and returns the cflags
// needed to build the package.
func pkgConfigFlags(p *build.Package) (cflags []string, err error) {
if len(p.CgoPkgConfig) == 0 {
return nil, nil
}
return pkgConfig("--cflags", p.CgoPkgConfig)
}

View File

@@ -0,0 +1,852 @@
// Copyright 2016 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.
// Binary package export.
// This file was derived from $GOROOT/src/cmd/compile/internal/gc/bexport.go;
// see that file for specification of the format.
package gcimporter
import (
"bytes"
"encoding/binary"
"fmt"
"go/ast"
"go/constant"
"go/token"
"go/types"
"math"
"math/big"
"sort"
"strings"
)
// If debugFormat is set, each integer and string value is preceded by a marker
// and position information in the encoding. This mechanism permits an importer
// to recognize immediately when it is out of sync. The importer recognizes this
// mode automatically (i.e., it can import export data produced with debugging
// support even if debugFormat is not set at the time of import). This mode will
// lead to massively larger export data (by a factor of 2 to 3) and should only
// be enabled during development and debugging.
//
// NOTE: This flag is the first flag to enable if importing dies because of
// (suspected) format errors, and whenever a change is made to the format.
const debugFormat = false // default: false
// If trace is set, debugging output is printed to std out.
const trace = false // default: false
// Current export format version. Increase with each format change.
// Note: The latest binary (non-indexed) export format is at version 6.
// This exporter is still at level 4, but it doesn't matter since
// the binary importer can handle older versions just fine.
// 6: package height (CL 105038) -- NOT IMPLEMENTED HERE
// 5: improved position encoding efficiency (issue 20080, CL 41619) -- NOT IMPLEMEMTED HERE
// 4: type name objects support type aliases, uses aliasTag
// 3: Go1.8 encoding (same as version 2, aliasTag defined but never used)
// 2: removed unused bool in ODCL export (compiler only)
// 1: header format change (more regular), export package for _ struct fields
// 0: Go1.7 encoding
const exportVersion = 4
// trackAllTypes enables cycle tracking for all types, not just named
// types. The existing compiler invariants assume that unnamed types
// that are not completely set up are not used, or else there are spurious
// errors.
// If disabled, only named types are tracked, possibly leading to slightly
// less efficient encoding in rare cases. It also prevents the export of
// some corner-case type declarations (but those are not handled correctly
// with with the textual export format either).
// TODO(gri) enable and remove once issues caused by it are fixed
const trackAllTypes = false
type exporter struct {
fset *token.FileSet
out bytes.Buffer
// object -> index maps, indexed in order of serialization
strIndex map[string]int
pkgIndex map[*types.Package]int
typIndex map[types.Type]int
// position encoding
posInfoFormat bool
prevFile string
prevLine int
// debugging support
written int // bytes written
indent int // for trace
}
// internalError represents an error generated inside this package.
type internalError string
func (e internalError) Error() string { return "gcimporter: " + string(e) }
func internalErrorf(format string, args ...interface{}) error {
return internalError(fmt.Sprintf(format, args...))
}
// BExportData returns binary export data for pkg.
// If no file set is provided, position info will be missing.
func BExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) {
defer func() {
if e := recover(); e != nil {
if ierr, ok := e.(internalError); ok {
err = ierr
return
}
// Not an internal error; panic again.
panic(e)
}
}()
p := exporter{
fset: fset,
strIndex: map[string]int{"": 0}, // empty string is mapped to 0
pkgIndex: make(map[*types.Package]int),
typIndex: make(map[types.Type]int),
posInfoFormat: true, // TODO(gri) might become a flag, eventually
}
// write version info
// The version string must start with "version %d" where %d is the version
// number. Additional debugging information may follow after a blank; that
// text is ignored by the importer.
p.rawStringln(fmt.Sprintf("version %d", exportVersion))
var debug string
if debugFormat {
debug = "debug"
}
p.rawStringln(debug) // cannot use p.bool since it's affected by debugFormat; also want to see this clearly
p.bool(trackAllTypes)
p.bool(p.posInfoFormat)
// --- generic export data ---
// populate type map with predeclared "known" types
for index, typ := range predeclared() {
p.typIndex[typ] = index
}
if len(p.typIndex) != len(predeclared()) {
return nil, internalError("duplicate entries in type map?")
}
// write package data
p.pkg(pkg, true)
if trace {
p.tracef("\n")
}
// write objects
objcount := 0
scope := pkg.Scope()
for _, name := range scope.Names() {
if !ast.IsExported(name) {
continue
}
if trace {
p.tracef("\n")
}
p.obj(scope.Lookup(name))
objcount++
}
// indicate end of list
if trace {
p.tracef("\n")
}
p.tag(endTag)
// for self-verification only (redundant)
p.int(objcount)
if trace {
p.tracef("\n")
}
// --- end of export data ---
return p.out.Bytes(), nil
}
func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
if pkg == nil {
panic(internalError("unexpected nil pkg"))
}
// if we saw the package before, write its index (>= 0)
if i, ok := p.pkgIndex[pkg]; ok {
p.index('P', i)
return
}
// otherwise, remember the package, write the package tag (< 0) and package data
if trace {
p.tracef("P%d = { ", len(p.pkgIndex))
defer p.tracef("} ")
}
p.pkgIndex[pkg] = len(p.pkgIndex)
p.tag(packageTag)
p.string(pkg.Name())
if emptypath {
p.string("")
} else {
p.string(pkg.Path())
}
}
func (p *exporter) obj(obj types.Object) {
switch obj := obj.(type) {
case *types.Const:
p.tag(constTag)
p.pos(obj)
p.qualifiedName(obj)
p.typ(obj.Type())
p.value(obj.Val())
case *types.TypeName:
if obj.IsAlias() {
p.tag(aliasTag)
p.pos(obj)
p.qualifiedName(obj)
} else {
p.tag(typeTag)
}
p.typ(obj.Type())
case *types.Var:
p.tag(varTag)
p.pos(obj)
p.qualifiedName(obj)
p.typ(obj.Type())
case *types.Func:
p.tag(funcTag)
p.pos(obj)
p.qualifiedName(obj)
sig := obj.Type().(*types.Signature)
p.paramList(sig.Params(), sig.Variadic())
p.paramList(sig.Results(), false)
default:
panic(internalErrorf("unexpected object %v (%T)", obj, obj))
}
}
func (p *exporter) pos(obj types.Object) {
if !p.posInfoFormat {
return
}
file, line := p.fileLine(obj)
if file == p.prevFile {
// common case: write line delta
// delta == 0 means different file or no line change
delta := line - p.prevLine
p.int(delta)
if delta == 0 {
p.int(-1) // -1 means no file change
}
} else {
// different file
p.int(0)
// Encode filename as length of common prefix with previous
// filename, followed by (possibly empty) suffix. Filenames
// frequently share path prefixes, so this can save a lot
// of space and make export data size less dependent on file
// path length. The suffix is unlikely to be empty because
// file names tend to end in ".go".
n := commonPrefixLen(p.prevFile, file)
p.int(n) // n >= 0
p.string(file[n:]) // write suffix only
p.prevFile = file
p.int(line)
}
p.prevLine = line
}
func (p *exporter) fileLine(obj types.Object) (file string, line int) {
if p.fset != nil {
pos := p.fset.Position(obj.Pos())
file = pos.Filename
line = pos.Line
}
return
}
func commonPrefixLen(a, b string) int {
if len(a) > len(b) {
a, b = b, a
}
// len(a) <= len(b)
i := 0
for i < len(a) && a[i] == b[i] {
i++
}
return i
}
func (p *exporter) qualifiedName(obj types.Object) {
p.string(obj.Name())
p.pkg(obj.Pkg(), false)
}
func (p *exporter) typ(t types.Type) {
if t == nil {
panic(internalError("nil type"))
}
// Possible optimization: Anonymous pointer types *T where
// T is a named type are common. We could canonicalize all
// such types *T to a single type PT = *T. This would lead
// to at most one *T entry in typIndex, and all future *T's
// would be encoded as the respective index directly. Would
// save 1 byte (pointerTag) per *T and reduce the typIndex
// size (at the cost of a canonicalization map). We can do
// this later, without encoding format change.
// if we saw the type before, write its index (>= 0)
if i, ok := p.typIndex[t]; ok {
p.index('T', i)
return
}
// otherwise, remember the type, write the type tag (< 0) and type data
if trackAllTypes {
if trace {
p.tracef("T%d = {>\n", len(p.typIndex))
defer p.tracef("<\n} ")
}
p.typIndex[t] = len(p.typIndex)
}
switch t := t.(type) {
case *types.Named:
if !trackAllTypes {
// if we don't track all types, track named types now
p.typIndex[t] = len(p.typIndex)
}
p.tag(namedTag)
p.pos(t.Obj())
p.qualifiedName(t.Obj())
p.typ(t.Underlying())
if !types.IsInterface(t) {
p.assocMethods(t)
}
case *types.Array:
p.tag(arrayTag)
p.int64(t.Len())
p.typ(t.Elem())
case *types.Slice:
p.tag(sliceTag)
p.typ(t.Elem())
case *dddSlice:
p.tag(dddTag)
p.typ(t.elem)
case *types.Struct:
p.tag(structTag)
p.fieldList(t)
case *types.Pointer:
p.tag(pointerTag)
p.typ(t.Elem())
case *types.Signature:
p.tag(signatureTag)
p.paramList(t.Params(), t.Variadic())
p.paramList(t.Results(), false)
case *types.Interface:
p.tag(interfaceTag)
p.iface(t)
case *types.Map:
p.tag(mapTag)
p.typ(t.Key())
p.typ(t.Elem())
case *types.Chan:
p.tag(chanTag)
p.int(int(3 - t.Dir())) // hack
p.typ(t.Elem())
default:
panic(internalErrorf("unexpected type %T: %s", t, t))
}
}
func (p *exporter) assocMethods(named *types.Named) {
// Sort methods (for determinism).
var methods []*types.Func
for i := 0; i < named.NumMethods(); i++ {
methods = append(methods, named.Method(i))
}
sort.Sort(methodsByName(methods))
p.int(len(methods))
if trace && methods != nil {
p.tracef("associated methods {>\n")
}
for i, m := range methods {
if trace && i > 0 {
p.tracef("\n")
}
p.pos(m)
name := m.Name()
p.string(name)
if !exported(name) {
p.pkg(m.Pkg(), false)
}
sig := m.Type().(*types.Signature)
p.paramList(types.NewTuple(sig.Recv()), false)
p.paramList(sig.Params(), sig.Variadic())
p.paramList(sig.Results(), false)
p.int(0) // dummy value for go:nointerface pragma - ignored by importer
}
if trace && methods != nil {
p.tracef("<\n} ")
}
}
type methodsByName []*types.Func
func (x methodsByName) Len() int { return len(x) }
func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() }
func (p *exporter) fieldList(t *types.Struct) {
if trace && t.NumFields() > 0 {
p.tracef("fields {>\n")
defer p.tracef("<\n} ")
}
p.int(t.NumFields())
for i := 0; i < t.NumFields(); i++ {
if trace && i > 0 {
p.tracef("\n")
}
p.field(t.Field(i))
p.string(t.Tag(i))
}
}
func (p *exporter) field(f *types.Var) {
if !f.IsField() {
panic(internalError("field expected"))
}
p.pos(f)
p.fieldName(f)
p.typ(f.Type())
}
func (p *exporter) iface(t *types.Interface) {
// TODO(gri): enable importer to load embedded interfaces,
// then emit Embeddeds and ExplicitMethods separately here.
p.int(0)
n := t.NumMethods()
if trace && n > 0 {
p.tracef("methods {>\n")
defer p.tracef("<\n} ")
}
p.int(n)
for i := 0; i < n; i++ {
if trace && i > 0 {
p.tracef("\n")
}
p.method(t.Method(i))
}
}
func (p *exporter) method(m *types.Func) {
sig := m.Type().(*types.Signature)
if sig.Recv() == nil {
panic(internalError("method expected"))
}
p.pos(m)
p.string(m.Name())
if m.Name() != "_" && !ast.IsExported(m.Name()) {
p.pkg(m.Pkg(), false)
}
// interface method; no need to encode receiver.
p.paramList(sig.Params(), sig.Variadic())
p.paramList(sig.Results(), false)
}
func (p *exporter) fieldName(f *types.Var) {
name := f.Name()
if f.Anonymous() {
// anonymous field - we distinguish between 3 cases:
// 1) field name matches base type name and is exported
// 2) field name matches base type name and is not exported
// 3) field name doesn't match base type name (alias name)
bname := basetypeName(f.Type())
if name == bname {
if ast.IsExported(name) {
name = "" // 1) we don't need to know the field name or package
} else {
name = "?" // 2) use unexported name "?" to force package export
}
} else {
// 3) indicate alias and export name as is
// (this requires an extra "@" but this is a rare case)
p.string("@")
}
}
p.string(name)
if name != "" && !ast.IsExported(name) {
p.pkg(f.Pkg(), false)
}
}
func basetypeName(typ types.Type) string {
switch typ := deref(typ).(type) {
case *types.Basic:
return typ.Name()
case *types.Named:
return typ.Obj().Name()
default:
return "" // unnamed type
}
}
func (p *exporter) paramList(params *types.Tuple, variadic bool) {
// use negative length to indicate unnamed parameters
// (look at the first parameter only since either all
// names are present or all are absent)
n := params.Len()
if n > 0 && params.At(0).Name() == "" {
n = -n
}
p.int(n)
for i := 0; i < params.Len(); i++ {
q := params.At(i)
t := q.Type()
if variadic && i == params.Len()-1 {
t = &dddSlice{t.(*types.Slice).Elem()}
}
p.typ(t)
if n > 0 {
name := q.Name()
p.string(name)
if name != "_" {
p.pkg(q.Pkg(), false)
}
}
p.string("") // no compiler-specific info
}
}
func (p *exporter) value(x constant.Value) {
if trace {
p.tracef("= ")
}
switch x.Kind() {
case constant.Bool:
tag := falseTag
if constant.BoolVal(x) {
tag = trueTag
}
p.tag(tag)
case constant.Int:
if v, exact := constant.Int64Val(x); exact {
// common case: x fits into an int64 - use compact encoding
p.tag(int64Tag)
p.int64(v)
return
}
// uncommon case: large x - use float encoding
// (powers of 2 will be encoded efficiently with exponent)
p.tag(floatTag)
p.float(constant.ToFloat(x))
case constant.Float:
p.tag(floatTag)
p.float(x)
case constant.Complex:
p.tag(complexTag)
p.float(constant.Real(x))
p.float(constant.Imag(x))
case constant.String:
p.tag(stringTag)
p.string(constant.StringVal(x))
case constant.Unknown:
// package contains type errors
p.tag(unknownTag)
default:
panic(internalErrorf("unexpected value %v (%T)", x, x))
}
}
func (p *exporter) float(x constant.Value) {
if x.Kind() != constant.Float {
panic(internalErrorf("unexpected constant %v, want float", x))
}
// extract sign (there is no -0)
sign := constant.Sign(x)
if sign == 0 {
// x == 0
p.int(0)
return
}
// x != 0
var f big.Float
if v, exact := constant.Float64Val(x); exact {
// float64
f.SetFloat64(v)
} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
// TODO(gri): add big.Rat accessor to constant.Value.
r := valueToRat(num)
f.SetRat(r.Quo(r, valueToRat(denom)))
} else {
// Value too large to represent as a fraction => inaccessible.
// TODO(gri): add big.Float accessor to constant.Value.
f.SetFloat64(math.MaxFloat64) // FIXME
}
// extract exponent such that 0.5 <= m < 1.0
var m big.Float
exp := f.MantExp(&m)
// extract mantissa as *big.Int
// - set exponent large enough so mant satisfies mant.IsInt()
// - get *big.Int from mant
m.SetMantExp(&m, int(m.MinPrec()))
mant, acc := m.Int(nil)
if acc != big.Exact {
panic(internalError("internal error"))
}
p.int(sign)
p.int(exp)
p.string(string(mant.Bytes()))
}
func valueToRat(x constant.Value) *big.Rat {
// Convert little-endian to big-endian.
// I can't believe this is necessary.
bytes := constant.Bytes(x)
for i := 0; i < len(bytes)/2; i++ {
bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
}
return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
}
func (p *exporter) bool(b bool) bool {
if trace {
p.tracef("[")
defer p.tracef("= %v] ", b)
}
x := 0
if b {
x = 1
}
p.int(x)
return b
}
// ----------------------------------------------------------------------------
// Low-level encoders
func (p *exporter) index(marker byte, index int) {
if index < 0 {
panic(internalError("invalid index < 0"))
}
if debugFormat {
p.marker('t')
}
if trace {
p.tracef("%c%d ", marker, index)
}
p.rawInt64(int64(index))
}
func (p *exporter) tag(tag int) {
if tag >= 0 {
panic(internalError("invalid tag >= 0"))
}
if debugFormat {
p.marker('t')
}
if trace {
p.tracef("%s ", tagString[-tag])
}
p.rawInt64(int64(tag))
}
func (p *exporter) int(x int) {
p.int64(int64(x))
}
func (p *exporter) int64(x int64) {
if debugFormat {
p.marker('i')
}
if trace {
p.tracef("%d ", x)
}
p.rawInt64(x)
}
func (p *exporter) string(s string) {
if debugFormat {
p.marker('s')
}
if trace {
p.tracef("%q ", s)
}
// if we saw the string before, write its index (>= 0)
// (the empty string is mapped to 0)
if i, ok := p.strIndex[s]; ok {
p.rawInt64(int64(i))
return
}
// otherwise, remember string and write its negative length and bytes
p.strIndex[s] = len(p.strIndex)
p.rawInt64(-int64(len(s)))
for i := 0; i < len(s); i++ {
p.rawByte(s[i])
}
}
// marker emits a marker byte and position information which makes
// it easy for a reader to detect if it is "out of sync". Used for
// debugFormat format only.
func (p *exporter) marker(m byte) {
p.rawByte(m)
// Enable this for help tracking down the location
// of an incorrect marker when running in debugFormat.
if false && trace {
p.tracef("#%d ", p.written)
}
p.rawInt64(int64(p.written))
}
// rawInt64 should only be used by low-level encoders.
func (p *exporter) rawInt64(x int64) {
var tmp [binary.MaxVarintLen64]byte
n := binary.PutVarint(tmp[:], x)
for i := 0; i < n; i++ {
p.rawByte(tmp[i])
}
}
// rawStringln should only be used to emit the initial version string.
func (p *exporter) rawStringln(s string) {
for i := 0; i < len(s); i++ {
p.rawByte(s[i])
}
p.rawByte('\n')
}
// rawByte is the bottleneck interface to write to p.out.
// rawByte escapes b as follows (any encoding does that
// hides '$'):
//
// '$' => '|' 'S'
// '|' => '|' '|'
//
// Necessary so other tools can find the end of the
// export data by searching for "$$".
// rawByte should only be used by low-level encoders.
func (p *exporter) rawByte(b byte) {
switch b {
case '$':
// write '$' as '|' 'S'
b = 'S'
fallthrough
case '|':
// write '|' as '|' '|'
p.out.WriteByte('|')
p.written++
}
p.out.WriteByte(b)
p.written++
}
// tracef is like fmt.Printf but it rewrites the format string
// to take care of indentation.
func (p *exporter) tracef(format string, args ...interface{}) {
if strings.ContainsAny(format, "<>\n") {
var buf bytes.Buffer
for i := 0; i < len(format); i++ {
// no need to deal with runes
ch := format[i]
switch ch {
case '>':
p.indent++
continue
case '<':
p.indent--
continue
}
buf.WriteByte(ch)
if ch == '\n' {
for j := p.indent; j > 0; j-- {
buf.WriteString(". ")
}
}
}
format = buf.String()
}
fmt.Printf(format, args...)
}
// Debugging support.
// (tagString is only used when tracing is enabled)
var tagString = [...]string{
// Packages
-packageTag: "package",
// Types
-namedTag: "named type",
-arrayTag: "array",
-sliceTag: "slice",
-dddTag: "ddd",
-structTag: "struct",
-pointerTag: "pointer",
-signatureTag: "signature",
-interfaceTag: "interface",
-mapTag: "map",
-chanTag: "chan",
// Values
-falseTag: "false",
-trueTag: "true",
-int64Tag: "int64",
-floatTag: "float",
-fractionTag: "fraction",
-complexTag: "complex",
-stringTag: "string",
-unknownTag: "unknown",
// Type aliases
-aliasTag: "alias",
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
// Copyright 2011 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.
// This file is a copy of $GOROOT/src/go/internal/gcimporter/exportdata.go.
// This file implements FindExportData.
package gcimporter
import (
"bufio"
"fmt"
"io"
"strconv"
"strings"
)
func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
// See $GOROOT/include/ar.h.
hdr := make([]byte, 16+12+6+6+8+10+2)
_, err = io.ReadFull(r, hdr)
if err != nil {
return
}
// leave for debugging
if false {
fmt.Printf("header: %s", hdr)
}
s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
size, err = strconv.Atoi(s)
if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
err = fmt.Errorf("invalid archive header")
return
}
name = strings.TrimSpace(string(hdr[:16]))
return
}
// FindExportData positions the reader r at the beginning of the
// export data section of an underlying GC-created object/archive
// file by reading from it. The reader must be positioned at the
// start of the file before calling this function. The hdr result
// is the string before the export data, either "$$" or "$$B".
//
func FindExportData(r *bufio.Reader) (hdr string, err error) {
// Read first line to make sure this is an object file.
line, err := r.ReadSlice('\n')
if err != nil {
err = fmt.Errorf("can't find export data (%v)", err)
return
}
if string(line) == "!<arch>\n" {
// Archive file. Scan to __.PKGDEF.
var name string
if name, _, err = readGopackHeader(r); err != nil {
return
}
// First entry should be __.PKGDEF.
if name != "__.PKGDEF" {
err = fmt.Errorf("go archive is missing __.PKGDEF")
return
}
// Read first line of __.PKGDEF data, so that line
// is once again the first line of the input.
if line, err = r.ReadSlice('\n'); err != nil {
err = fmt.Errorf("can't find export data (%v)", err)
return
}
}
// Now at __.PKGDEF in archive or still at beginning of file.
// Either way, line should begin with "go object ".
if !strings.HasPrefix(string(line), "go object ") {
err = fmt.Errorf("not a Go object file")
return
}
// Skip over object header to export data.
// Begins after first line starting with $$.
for line[0] != '$' {
if line, err = r.ReadSlice('\n'); err != nil {
err = fmt.Errorf("can't find export data (%v)", err)
return
}
}
hdr = string(line)
return
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,723 @@
// Copyright 2019 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.
// Indexed binary package export.
// This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go;
// see that file for specification of the format.
// +build go1.11
package gcimporter
import (
"bytes"
"encoding/binary"
"go/ast"
"go/constant"
"go/token"
"go/types"
"io"
"math/big"
"reflect"
"sort"
)
// Current indexed export format version. Increase with each format change.
// 0: Go1.11 encoding
const iexportVersion = 0
// IExportData returns the binary export data for pkg.
// If no file set is provided, position info will be missing.
func IExportData(fset *token.FileSet, pkg *types.Package) (b []byte, err error) {
defer func() {
if e := recover(); e != nil {
if ierr, ok := e.(internalError); ok {
err = ierr
return
}
// Not an internal error; panic again.
panic(e)
}
}()
p := iexporter{
out: bytes.NewBuffer(nil),
fset: fset,
allPkgs: map[*types.Package]bool{},
stringIndex: map[string]uint64{},
declIndex: map[types.Object]uint64{},
typIndex: map[types.Type]uint64{},
}
for i, pt := range predeclared() {
p.typIndex[pt] = uint64(i)
}
if len(p.typIndex) > predeclReserved {
panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved))
}
// Initialize work queue with exported declarations.
scope := pkg.Scope()
for _, name := range scope.Names() {
if ast.IsExported(name) {
p.pushDecl(scope.Lookup(name))
}
}
// Loop until no more work.
for !p.declTodo.empty() {
p.doDecl(p.declTodo.popHead())
}
// Append indices to data0 section.
dataLen := uint64(p.data0.Len())
w := p.newWriter()
w.writeIndex(p.declIndex, pkg)
w.flush()
// Assemble header.
var hdr intWriter
hdr.WriteByte('i')
hdr.uint64(iexportVersion)
hdr.uint64(uint64(p.strings.Len()))
hdr.uint64(dataLen)
// Flush output.
io.Copy(p.out, &hdr)
io.Copy(p.out, &p.strings)
io.Copy(p.out, &p.data0)
return p.out.Bytes(), nil
}
// writeIndex writes out an object index. mainIndex indicates whether
// we're writing out the main index, which is also read by
// non-compiler tools and includes a complete package description
// (i.e., name and height).
func (w *exportWriter) writeIndex(index map[types.Object]uint64, localpkg *types.Package) {
// Build a map from packages to objects from that package.
pkgObjs := map[*types.Package][]types.Object{}
// For the main index, make sure to include every package that
// we reference, even if we're not exporting (or reexporting)
// any symbols from it.
pkgObjs[localpkg] = nil
for pkg := range w.p.allPkgs {
pkgObjs[pkg] = nil
}
for obj := range index {
pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], obj)
}
var pkgs []*types.Package
for pkg, objs := range pkgObjs {
pkgs = append(pkgs, pkg)
sort.Slice(objs, func(i, j int) bool {
return objs[i].Name() < objs[j].Name()
})
}
sort.Slice(pkgs, func(i, j int) bool {
return pkgs[i].Path() < pkgs[j].Path()
})
w.uint64(uint64(len(pkgs)))
for _, pkg := range pkgs {
w.string(pkg.Path())
w.string(pkg.Name())
w.uint64(uint64(0)) // package height is not needed for go/types
objs := pkgObjs[pkg]
w.uint64(uint64(len(objs)))
for _, obj := range objs {
w.string(obj.Name())
w.uint64(index[obj])
}
}
}
type iexporter struct {
fset *token.FileSet
out *bytes.Buffer
// allPkgs tracks all packages that have been referenced by
// the export data, so we can ensure to include them in the
// main index.
allPkgs map[*types.Package]bool
declTodo objQueue
strings intWriter
stringIndex map[string]uint64
data0 intWriter
declIndex map[types.Object]uint64
typIndex map[types.Type]uint64
}
// stringOff returns the offset of s within the string section.
// If not already present, it's added to the end.
func (p *iexporter) stringOff(s string) uint64 {
off, ok := p.stringIndex[s]
if !ok {
off = uint64(p.strings.Len())
p.stringIndex[s] = off
p.strings.uint64(uint64(len(s)))
p.strings.WriteString(s)
}
return off
}
// pushDecl adds n to the declaration work queue, if not already present.
func (p *iexporter) pushDecl(obj types.Object) {
// Package unsafe is known to the compiler and predeclared.
assert(obj.Pkg() != types.Unsafe)
if _, ok := p.declIndex[obj]; ok {
return
}
p.declIndex[obj] = ^uint64(0) // mark n present in work queue
p.declTodo.pushTail(obj)
}
// exportWriter handles writing out individual data section chunks.
type exportWriter struct {
p *iexporter
data intWriter
currPkg *types.Package
prevFile string
prevLine int64
}
func (p *iexporter) doDecl(obj types.Object) {
w := p.newWriter()
w.setPkg(obj.Pkg(), false)
switch obj := obj.(type) {
case *types.Var:
w.tag('V')
w.pos(obj.Pos())
w.typ(obj.Type(), obj.Pkg())
case *types.Func:
sig, _ := obj.Type().(*types.Signature)
if sig.Recv() != nil {
panic(internalErrorf("unexpected method: %v", sig))
}
w.tag('F')
w.pos(obj.Pos())
w.signature(sig)
case *types.Const:
w.tag('C')
w.pos(obj.Pos())
w.value(obj.Type(), obj.Val())
case *types.TypeName:
if obj.IsAlias() {
w.tag('A')
w.pos(obj.Pos())
w.typ(obj.Type(), obj.Pkg())
break
}
// Defined type.
w.tag('T')
w.pos(obj.Pos())
underlying := obj.Type().Underlying()
w.typ(underlying, obj.Pkg())
t := obj.Type()
if types.IsInterface(t) {
break
}
named, ok := t.(*types.Named)
if !ok {
panic(internalErrorf("%s is not a defined type", t))
}
n := named.NumMethods()
w.uint64(uint64(n))
for i := 0; i < n; i++ {
m := named.Method(i)
w.pos(m.Pos())
w.string(m.Name())
sig, _ := m.Type().(*types.Signature)
w.param(sig.Recv())
w.signature(sig)
}
default:
panic(internalErrorf("unexpected object: %v", obj))
}
p.declIndex[obj] = w.flush()
}
func (w *exportWriter) tag(tag byte) {
w.data.WriteByte(tag)
}
func (w *exportWriter) pos(pos token.Pos) {
p := w.p.fset.Position(pos)
file := p.Filename
line := int64(p.Line)
// When file is the same as the last position (common case),
// we can save a few bytes by delta encoding just the line
// number.
//
// Note: Because data objects may be read out of order (or not
// at all), we can only apply delta encoding within a single
// object. This is handled implicitly by tracking prevFile and
// prevLine as fields of exportWriter.
if file == w.prevFile {
delta := line - w.prevLine
w.int64(delta)
if delta == deltaNewFile {
w.int64(-1)
}
} else {
w.int64(deltaNewFile)
w.int64(line) // line >= 0
w.string(file)
w.prevFile = file
}
w.prevLine = line
}
func (w *exportWriter) pkg(pkg *types.Package) {
// Ensure any referenced packages are declared in the main index.
w.p.allPkgs[pkg] = true
w.string(pkg.Path())
}
func (w *exportWriter) qualifiedIdent(obj types.Object) {
// Ensure any referenced declarations are written out too.
w.p.pushDecl(obj)
w.string(obj.Name())
w.pkg(obj.Pkg())
}
func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
w.data.uint64(w.p.typOff(t, pkg))
}
func (p *iexporter) newWriter() *exportWriter {
return &exportWriter{p: p}
}
func (w *exportWriter) flush() uint64 {
off := uint64(w.p.data0.Len())
io.Copy(&w.p.data0, &w.data)
return off
}
func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 {
off, ok := p.typIndex[t]
if !ok {
w := p.newWriter()
w.doTyp(t, pkg)
off = predeclReserved + w.flush()
p.typIndex[t] = off
}
return off
}
func (w *exportWriter) startType(k itag) {
w.data.uint64(uint64(k))
}
func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
switch t := t.(type) {
case *types.Named:
w.startType(definedType)
w.qualifiedIdent(t.Obj())
case *types.Pointer:
w.startType(pointerType)
w.typ(t.Elem(), pkg)
case *types.Slice:
w.startType(sliceType)
w.typ(t.Elem(), pkg)
case *types.Array:
w.startType(arrayType)
w.uint64(uint64(t.Len()))
w.typ(t.Elem(), pkg)
case *types.Chan:
w.startType(chanType)
// 1 RecvOnly; 2 SendOnly; 3 SendRecv
var dir uint64
switch t.Dir() {
case types.RecvOnly:
dir = 1
case types.SendOnly:
dir = 2
case types.SendRecv:
dir = 3
}
w.uint64(dir)
w.typ(t.Elem(), pkg)
case *types.Map:
w.startType(mapType)
w.typ(t.Key(), pkg)
w.typ(t.Elem(), pkg)
case *types.Signature:
w.startType(signatureType)
w.setPkg(pkg, true)
w.signature(t)
case *types.Struct:
w.startType(structType)
w.setPkg(pkg, true)
n := t.NumFields()
w.uint64(uint64(n))
for i := 0; i < n; i++ {
f := t.Field(i)
w.pos(f.Pos())
w.string(f.Name())
w.typ(f.Type(), pkg)
w.bool(f.Embedded())
w.string(t.Tag(i)) // note (or tag)
}
case *types.Interface:
w.startType(interfaceType)
w.setPkg(pkg, true)
n := t.NumEmbeddeds()
w.uint64(uint64(n))
for i := 0; i < n; i++ {
f := t.Embedded(i)
w.pos(f.Obj().Pos())
w.typ(f.Obj().Type(), f.Obj().Pkg())
}
n = t.NumExplicitMethods()
w.uint64(uint64(n))
for i := 0; i < n; i++ {
m := t.ExplicitMethod(i)
w.pos(m.Pos())
w.string(m.Name())
sig, _ := m.Type().(*types.Signature)
w.signature(sig)
}
default:
panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
}
}
func (w *exportWriter) setPkg(pkg *types.Package, write bool) {
if write {
w.pkg(pkg)
}
w.currPkg = pkg
}
func (w *exportWriter) signature(sig *types.Signature) {
w.paramList(sig.Params())
w.paramList(sig.Results())
if sig.Params().Len() > 0 {
w.bool(sig.Variadic())
}
}
func (w *exportWriter) paramList(tup *types.Tuple) {
n := tup.Len()
w.uint64(uint64(n))
for i := 0; i < n; i++ {
w.param(tup.At(i))
}
}
func (w *exportWriter) param(obj types.Object) {
w.pos(obj.Pos())
w.localIdent(obj)
w.typ(obj.Type(), obj.Pkg())
}
func (w *exportWriter) value(typ types.Type, v constant.Value) {
w.typ(typ, nil)
switch v.Kind() {
case constant.Bool:
w.bool(constant.BoolVal(v))
case constant.Int:
var i big.Int
if i64, exact := constant.Int64Val(v); exact {
i.SetInt64(i64)
} else if ui64, exact := constant.Uint64Val(v); exact {
i.SetUint64(ui64)
} else {
i.SetString(v.ExactString(), 10)
}
w.mpint(&i, typ)
case constant.Float:
f := constantToFloat(v)
w.mpfloat(f, typ)
case constant.Complex:
w.mpfloat(constantToFloat(constant.Real(v)), typ)
w.mpfloat(constantToFloat(constant.Imag(v)), typ)
case constant.String:
w.string(constant.StringVal(v))
case constant.Unknown:
// package contains type errors
default:
panic(internalErrorf("unexpected value %v (%T)", v, v))
}
}
// constantToFloat converts a constant.Value with kind constant.Float to a
// big.Float.
func constantToFloat(x constant.Value) *big.Float {
assert(x.Kind() == constant.Float)
// Use the same floating-point precision (512) as cmd/compile
// (see Mpprec in cmd/compile/internal/gc/mpfloat.go).
const mpprec = 512
var f big.Float
f.SetPrec(mpprec)
if v, exact := constant.Float64Val(x); exact {
// float64
f.SetFloat64(v)
} else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
// TODO(gri): add big.Rat accessor to constant.Value.
n := valueToRat(num)
d := valueToRat(denom)
f.SetRat(n.Quo(n, d))
} else {
// Value too large to represent as a fraction => inaccessible.
// TODO(gri): add big.Float accessor to constant.Value.
_, ok := f.SetString(x.ExactString())
assert(ok)
}
return &f
}
// mpint exports a multi-precision integer.
//
// For unsigned types, small values are written out as a single
// byte. Larger values are written out as a length-prefixed big-endian
// byte string, where the length prefix is encoded as its complement.
// For example, bytes 0, 1, and 2 directly represent the integer
// values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-,
// 2-, and 3-byte big-endian string follow.
//
// Encoding for signed types use the same general approach as for
// unsigned types, except small values use zig-zag encoding and the
// bottom bit of length prefix byte for large values is reserved as a
// sign bit.
//
// The exact boundary between small and large encodings varies
// according to the maximum number of bytes needed to encode a value
// of type typ. As a special case, 8-bit types are always encoded as a
// single byte.
//
// TODO(mdempsky): Is this level of complexity really worthwhile?
func (w *exportWriter) mpint(x *big.Int, typ types.Type) {
basic, ok := typ.Underlying().(*types.Basic)
if !ok {
panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying()))
}
signed, maxBytes := intSize(basic)
negative := x.Sign() < 0
if !signed && negative {
panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x))
}
b := x.Bytes()
if len(b) > 0 && b[0] == 0 {
panic(internalErrorf("leading zeros"))
}
if uint(len(b)) > maxBytes {
panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x))
}
maxSmall := 256 - maxBytes
if signed {
maxSmall = 256 - 2*maxBytes
}
if maxBytes == 1 {
maxSmall = 256
}
// Check if x can use small value encoding.
if len(b) <= 1 {
var ux uint
if len(b) == 1 {
ux = uint(b[0])
}
if signed {
ux <<= 1
if negative {
ux--
}
}
if ux < maxSmall {
w.data.WriteByte(byte(ux))
return
}
}
n := 256 - uint(len(b))
if signed {
n = 256 - 2*uint(len(b))
if negative {
n |= 1
}
}
if n < maxSmall || n >= 256 {
panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n))
}
w.data.WriteByte(byte(n))
w.data.Write(b)
}
// mpfloat exports a multi-precision floating point number.
//
// The number's value is decomposed into mantissa × 2**exponent, where
// mantissa is an integer. The value is written out as mantissa (as a
// multi-precision integer) and then the exponent, except exponent is
// omitted if mantissa is zero.
func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) {
if f.IsInf() {
panic("infinite constant")
}
// Break into f = mant × 2**exp, with 0.5 <= mant < 1.
var mant big.Float
exp := int64(f.MantExp(&mant))
// Scale so that mant is an integer.
prec := mant.MinPrec()
mant.SetMantExp(&mant, int(prec))
exp -= int64(prec)
manti, acc := mant.Int(nil)
if acc != big.Exact {
panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc))
}
w.mpint(manti, typ)
if manti.Sign() != 0 {
w.int64(exp)
}
}
func (w *exportWriter) bool(b bool) bool {
var x uint64
if b {
x = 1
}
w.uint64(x)
return b
}
func (w *exportWriter) int64(x int64) { w.data.int64(x) }
func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
func (w *exportWriter) localIdent(obj types.Object) {
// Anonymous parameters.
if obj == nil {
w.string("")
return
}
name := obj.Name()
if name == "_" {
w.string("_")
return
}
w.string(name)
}
type intWriter struct {
bytes.Buffer
}
func (w *intWriter) int64(x int64) {
var buf [binary.MaxVarintLen64]byte
n := binary.PutVarint(buf[:], x)
w.Write(buf[:n])
}
func (w *intWriter) uint64(x uint64) {
var buf [binary.MaxVarintLen64]byte
n := binary.PutUvarint(buf[:], x)
w.Write(buf[:n])
}
func assert(cond bool) {
if !cond {
panic("internal error: assertion failed")
}
}
// The below is copied from go/src/cmd/compile/internal/gc/syntax.go.
// objQueue is a FIFO queue of types.Object. The zero value of objQueue is
// a ready-to-use empty queue.
type objQueue struct {
ring []types.Object
head, tail int
}
// empty returns true if q contains no Nodes.
func (q *objQueue) empty() bool {
return q.head == q.tail
}
// pushTail appends n to the tail of the queue.
func (q *objQueue) pushTail(obj types.Object) {
if len(q.ring) == 0 {
q.ring = make([]types.Object, 16)
} else if q.head+len(q.ring) == q.tail {
// Grow the ring.
nring := make([]types.Object, len(q.ring)*2)
// Copy the old elements.
part := q.ring[q.head%len(q.ring):]
if q.tail-q.head <= len(part) {
part = part[:q.tail-q.head]
copy(nring, part)
} else {
pos := copy(nring, part)
copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
}
q.ring, q.head, q.tail = nring, 0, q.tail-q.head
}
q.ring[q.tail%len(q.ring)] = obj
q.tail++
}
// popHead pops a node from the head of the queue. It panics if q is empty.
func (q *objQueue) popHead() types.Object {
if q.empty() {
panic("dequeue empty")
}
obj := q.ring[q.head%len(q.ring)]
q.head++
return obj
}

View File

@@ -0,0 +1,606 @@
// 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.
// Indexed package import.
// See cmd/compile/internal/gc/iexport.go for the export data format.
// This file is a copy of $GOROOT/src/go/internal/gcimporter/iimport.go.
package gcimporter
import (
"bytes"
"encoding/binary"
"fmt"
"go/constant"
"go/token"
"go/types"
"io"
"sort"
)
type intReader struct {
*bytes.Reader
path string
}
func (r *intReader) int64() int64 {
i, err := binary.ReadVarint(r.Reader)
if err != nil {
errorf("import %q: read varint error: %v", r.path, err)
}
return i
}
func (r *intReader) uint64() uint64 {
i, err := binary.ReadUvarint(r.Reader)
if err != nil {
errorf("import %q: read varint error: %v", r.path, err)
}
return i
}
const predeclReserved = 32
type itag uint64
const (
// Types
definedType itag = iota
pointerType
sliceType
arrayType
chanType
mapType
signatureType
structType
interfaceType
)
// IImportData imports a package from the serialized package data
// and returns the number of bytes consumed and a reference to the package.
// If the export data version is not recognized or the format is otherwise
// compromised, an error is returned.
func IImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
const currentVersion = 0
version := -1
defer func() {
if e := recover(); e != nil {
if version > currentVersion {
err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
} else {
err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
}
}
}()
r := &intReader{bytes.NewReader(data), path}
version = int(r.uint64())
switch version {
case currentVersion:
default:
errorf("unknown iexport format version %d", version)
}
sLen := int64(r.uint64())
dLen := int64(r.uint64())
whence, _ := r.Seek(0, io.SeekCurrent)
stringData := data[whence : whence+sLen]
declData := data[whence+sLen : whence+sLen+dLen]
r.Seek(sLen+dLen, io.SeekCurrent)
p := iimporter{
ipath: path,
stringData: stringData,
stringCache: make(map[uint64]string),
pkgCache: make(map[uint64]*types.Package),
declData: declData,
pkgIndex: make(map[*types.Package]map[string]uint64),
typCache: make(map[uint64]types.Type),
fake: fakeFileSet{
fset: fset,
files: make(map[string]*token.File),
},
}
for i, pt := range predeclared() {
p.typCache[uint64(i)] = pt
}
pkgList := make([]*types.Package, r.uint64())
for i := range pkgList {
pkgPathOff := r.uint64()
pkgPath := p.stringAt(pkgPathOff)
pkgName := p.stringAt(r.uint64())
_ = r.uint64() // package height; unused by go/types
if pkgPath == "" {
pkgPath = path
}
pkg := imports[pkgPath]
if pkg == nil {
pkg = types.NewPackage(pkgPath, pkgName)
imports[pkgPath] = pkg
} else if pkg.Name() != pkgName {
errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
}
p.pkgCache[pkgPathOff] = pkg
nameIndex := make(map[string]uint64)
for nSyms := r.uint64(); nSyms > 0; nSyms-- {
name := p.stringAt(r.uint64())
nameIndex[name] = r.uint64()
}
p.pkgIndex[pkg] = nameIndex
pkgList[i] = pkg
}
var localpkg *types.Package
for _, pkg := range pkgList {
if pkg.Path() == path {
localpkg = pkg
}
}
names := make([]string, 0, len(p.pkgIndex[localpkg]))
for name := range p.pkgIndex[localpkg] {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
p.doDecl(localpkg, name)
}
for _, typ := range p.interfaceList {
typ.Complete()
}
// record all referenced packages as imports
list := append(([]*types.Package)(nil), pkgList[1:]...)
sort.Sort(byPath(list))
localpkg.SetImports(list)
// package was imported completely and without errors
localpkg.MarkComplete()
consumed, _ := r.Seek(0, io.SeekCurrent)
return int(consumed), localpkg, nil
}
type iimporter struct {
ipath string
stringData []byte
stringCache map[uint64]string
pkgCache map[uint64]*types.Package
declData []byte
pkgIndex map[*types.Package]map[string]uint64
typCache map[uint64]types.Type
fake fakeFileSet
interfaceList []*types.Interface
}
func (p *iimporter) doDecl(pkg *types.Package, name string) {
// See if we've already imported this declaration.
if obj := pkg.Scope().Lookup(name); obj != nil {
return
}
off, ok := p.pkgIndex[pkg][name]
if !ok {
errorf("%v.%v not in index", pkg, name)
}
r := &importReader{p: p, currPkg: pkg}
r.declReader.Reset(p.declData[off:])
r.obj(name)
}
func (p *iimporter) stringAt(off uint64) string {
if s, ok := p.stringCache[off]; ok {
return s
}
slen, n := binary.Uvarint(p.stringData[off:])
if n <= 0 {
errorf("varint failed")
}
spos := off + uint64(n)
s := string(p.stringData[spos : spos+slen])
p.stringCache[off] = s
return s
}
func (p *iimporter) pkgAt(off uint64) *types.Package {
if pkg, ok := p.pkgCache[off]; ok {
return pkg
}
path := p.stringAt(off)
errorf("missing package %q in %q", path, p.ipath)
return nil
}
func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) {
return t
}
if off < predeclReserved {
errorf("predeclared type missing from cache: %v", off)
}
r := &importReader{p: p}
r.declReader.Reset(p.declData[off-predeclReserved:])
t := r.doType(base)
if base == nil || !isInterface(t) {
p.typCache[off] = t
}
return t
}
type importReader struct {
p *iimporter
declReader bytes.Reader
currPkg *types.Package
prevFile string
prevLine int64
}
func (r *importReader) obj(name string) {
tag := r.byte()
pos := r.pos()
switch tag {
case 'A':
typ := r.typ()
r.declare(types.NewTypeName(pos, r.currPkg, name, typ))
case 'C':
typ, val := r.value()
r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
case 'F':
sig := r.signature(nil)
r.declare(types.NewFunc(pos, r.currPkg, name, sig))
case 'T':
// Types can be recursive. We need to setup a stub
// declaration before recursing.
obj := types.NewTypeName(pos, r.currPkg, name, nil)
named := types.NewNamed(obj, nil, nil)
r.declare(obj)
underlying := r.p.typAt(r.uint64(), named).Underlying()
named.SetUnderlying(underlying)
if !isInterface(underlying) {
for n := r.uint64(); n > 0; n-- {
mpos := r.pos()
mname := r.ident()
recv := r.param()
msig := r.signature(recv)
named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
}
}
case 'V':
typ := r.typ()
r.declare(types.NewVar(pos, r.currPkg, name, typ))
default:
errorf("unexpected tag: %v", tag)
}
}
func (r *importReader) declare(obj types.Object) {
obj.Pkg().Scope().Insert(obj)
}
func (r *importReader) value() (typ types.Type, val constant.Value) {
typ = r.typ()
switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
case types.IsBoolean:
val = constant.MakeBool(r.bool())
case types.IsString:
val = constant.MakeString(r.string())
case types.IsInteger:
val = r.mpint(b)
case types.IsFloat:
val = r.mpfloat(b)
case types.IsComplex:
re := r.mpfloat(b)
im := r.mpfloat(b)
val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
default:
if b.Kind() == types.Invalid {
val = constant.MakeUnknown()
return
}
errorf("unexpected type %v", typ) // panics
panic("unreachable")
}
return
}
func intSize(b *types.Basic) (signed bool, maxBytes uint) {
if (b.Info() & types.IsUntyped) != 0 {
return true, 64
}
switch b.Kind() {
case types.Float32, types.Complex64:
return true, 3
case types.Float64, types.Complex128:
return true, 7
}
signed = (b.Info() & types.IsUnsigned) == 0
switch b.Kind() {
case types.Int8, types.Uint8:
maxBytes = 1
case types.Int16, types.Uint16:
maxBytes = 2
case types.Int32, types.Uint32:
maxBytes = 4
default:
maxBytes = 8
}
return
}
func (r *importReader) mpint(b *types.Basic) constant.Value {
signed, maxBytes := intSize(b)
maxSmall := 256 - maxBytes
if signed {
maxSmall = 256 - 2*maxBytes
}
if maxBytes == 1 {
maxSmall = 256
}
n, _ := r.declReader.ReadByte()
if uint(n) < maxSmall {
v := int64(n)
if signed {
v >>= 1
if n&1 != 0 {
v = ^v
}
}
return constant.MakeInt64(v)
}
v := -n
if signed {
v = -(n &^ 1) >> 1
}
if v < 1 || uint(v) > maxBytes {
errorf("weird decoding: %v, %v => %v", n, signed, v)
}
buf := make([]byte, v)
io.ReadFull(&r.declReader, buf)
// convert to little endian
// TODO(gri) go/constant should have a more direct conversion function
// (e.g., once it supports a big.Float based implementation)
for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
buf[i], buf[j] = buf[j], buf[i]
}
x := constant.MakeFromBytes(buf)
if signed && n&1 != 0 {
x = constant.UnaryOp(token.SUB, x, 0)
}
return x
}
func (r *importReader) mpfloat(b *types.Basic) constant.Value {
x := r.mpint(b)
if constant.Sign(x) == 0 {
return x
}
exp := r.int64()
switch {
case exp > 0:
x = constant.Shift(x, token.SHL, uint(exp))
case exp < 0:
d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
x = constant.BinaryOp(x, token.QUO, d)
}
return x
}
func (r *importReader) ident() string {
return r.string()
}
func (r *importReader) qualifiedIdent() (*types.Package, string) {
name := r.string()
pkg := r.pkg()
return pkg, name
}
func (r *importReader) pos() token.Pos {
delta := r.int64()
if delta != deltaNewFile {
r.prevLine += delta
} else if l := r.int64(); l == -1 {
r.prevLine += deltaNewFile
} else {
r.prevFile = r.string()
r.prevLine = l
}
if r.prevFile == "" && r.prevLine == 0 {
return token.NoPos
}
return r.p.fake.pos(r.prevFile, int(r.prevLine))
}
func (r *importReader) typ() types.Type {
return r.p.typAt(r.uint64(), nil)
}
func isInterface(t types.Type) bool {
_, ok := t.(*types.Interface)
return ok
}
func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) }
func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
func (r *importReader) doType(base *types.Named) types.Type {
switch k := r.kind(); k {
default:
errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
return nil
case definedType:
pkg, name := r.qualifiedIdent()
r.p.doDecl(pkg, name)
return pkg.Scope().Lookup(name).(*types.TypeName).Type()
case pointerType:
return types.NewPointer(r.typ())
case sliceType:
return types.NewSlice(r.typ())
case arrayType:
n := r.uint64()
return types.NewArray(r.typ(), int64(n))
case chanType:
dir := chanDir(int(r.uint64()))
return types.NewChan(dir, r.typ())
case mapType:
return types.NewMap(r.typ(), r.typ())
case signatureType:
r.currPkg = r.pkg()
return r.signature(nil)
case structType:
r.currPkg = r.pkg()
fields := make([]*types.Var, r.uint64())
tags := make([]string, len(fields))
for i := range fields {
fpos := r.pos()
fname := r.ident()
ftyp := r.typ()
emb := r.bool()
tag := r.string()
fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb)
tags[i] = tag
}
return types.NewStruct(fields, tags)
case interfaceType:
r.currPkg = r.pkg()
embeddeds := make([]types.Type, r.uint64())
for i := range embeddeds {
_ = r.pos()
embeddeds[i] = r.typ()
}
methods := make([]*types.Func, r.uint64())
for i := range methods {
mpos := r.pos()
mname := r.ident()
// TODO(mdempsky): Matches bimport.go, but I
// don't agree with this.
var recv *types.Var
if base != nil {
recv = types.NewVar(token.NoPos, r.currPkg, "", base)
}
msig := r.signature(recv)
methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
}
typ := newInterface(methods, embeddeds)
r.p.interfaceList = append(r.p.interfaceList, typ)
return typ
}
}
func (r *importReader) kind() itag {
return itag(r.uint64())
}
func (r *importReader) signature(recv *types.Var) *types.Signature {
params := r.paramList()
results := r.paramList()
variadic := params.Len() > 0 && r.bool()
return types.NewSignature(recv, params, results, variadic)
}
func (r *importReader) paramList() *types.Tuple {
xs := make([]*types.Var, r.uint64())
for i := range xs {
xs[i] = r.param()
}
return types.NewTuple(xs...)
}
func (r *importReader) param() *types.Var {
pos := r.pos()
name := r.ident()
typ := r.typ()
return types.NewParam(pos, r.currPkg, name, typ)
}
func (r *importReader) bool() bool {
return r.uint64() != 0
}
func (r *importReader) int64() int64 {
n, err := binary.ReadVarint(&r.declReader)
if err != nil {
errorf("readVarint: %v", err)
}
return n
}
func (r *importReader) uint64() uint64 {
n, err := binary.ReadUvarint(&r.declReader)
if err != nil {
errorf("readUvarint: %v", err)
}
return n
}
func (r *importReader) byte() byte {
x, err := r.declReader.ReadByte()
if err != nil {
errorf("declReader.ReadByte: %v", err)
}
return x
}

View File

@@ -0,0 +1,21 @@
// 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.
// +build !go1.11
package gcimporter
import "go/types"
func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface {
named := make([]*types.Named, len(embeddeds))
for i, e := range embeddeds {
var ok bool
named[i], ok = e.(*types.Named)
if !ok {
panic("embedding of non-defined interfaces in interfaces is not supported before Go 1.11")
}
}
return types.NewInterface(methods, named)
}

View File

@@ -0,0 +1,13 @@
// 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.
// +build go1.11
package gcimporter
import "go/types"
func newInterface(methods []*types.Func, embeddeds []types.Type) *types.Interface {
return types.NewInterfaceType(methods, embeddeds)
}

View File

@@ -0,0 +1,160 @@
// 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 packagesdriver fetches type sizes for go/packages and go/analysis.
package packagesdriver
import (
"bytes"
"context"
"encoding/json"
"fmt"
"go/types"
"log"
"os"
"os/exec"
"strings"
"time"
)
var debug = false
// GetSizes returns the sizes used by the underlying driver with the given parameters.
func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) {
// TODO(matloob): Clean this up. This code is mostly a copy of packages.findExternalDriver.
const toolPrefix = "GOPACKAGESDRIVER="
tool := ""
for _, env := range env {
if val := strings.TrimPrefix(env, toolPrefix); val != env {
tool = val
}
}
if tool == "" {
var err error
tool, err = exec.LookPath("gopackagesdriver")
if err != nil {
// We did not find the driver, so use "go list".
tool = "off"
}
}
if tool == "off" {
return GetSizesGolist(ctx, buildFlags, env, dir, usesExportData)
}
req, err := json.Marshal(struct {
Command string `json:"command"`
Env []string `json:"env"`
BuildFlags []string `json:"build_flags"`
}{
Command: "sizes",
Env: env,
BuildFlags: buildFlags,
})
if err != nil {
return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)
}
buf := new(bytes.Buffer)
cmd := exec.CommandContext(ctx, tool)
cmd.Dir = dir
cmd.Env = env
cmd.Stdin = bytes.NewReader(req)
cmd.Stdout = buf
cmd.Stderr = new(bytes.Buffer)
if err := cmd.Run(); err != nil {
return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
}
var response struct {
// Sizes, if not nil, is the types.Sizes to use when type checking.
Sizes *types.StdSizes
}
if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
return nil, err
}
return response.Sizes, nil
}
func GetSizesGolist(ctx context.Context, buildFlags, env []string, dir string, usesExportData bool) (types.Sizes, error) {
args := []string{"list", "-f", "{{context.GOARCH}} {{context.Compiler}}"}
args = append(args, buildFlags...)
args = append(args, "--", "unsafe")
stdout, err := InvokeGo(ctx, env, dir, usesExportData, args...)
if err != nil {
return nil, err
}
fields := strings.Fields(stdout.String())
if len(fields) < 2 {
return nil, fmt.Errorf("could not determine GOARCH and Go compiler")
}
goarch := fields[0]
compiler := fields[1]
return types.SizesFor(compiler, goarch), nil
}
// InvokeGo returns the stdout of a go command invocation.
func InvokeGo(ctx context.Context, env []string, dir string, usesExportData bool, args ...string) (*bytes.Buffer, error) {
if debug {
defer func(start time.Time) { log.Printf("%s for %v", time.Since(start), cmdDebugStr(env, args...)) }(time.Now())
}
stdout := new(bytes.Buffer)
stderr := new(bytes.Buffer)
cmd := exec.CommandContext(ctx, "go", args...)
// On darwin the cwd gets resolved to the real path, which breaks anything that
// expects the working directory to keep the original path, including the
// go command when dealing with modules.
// The Go stdlib has a special feature where if the cwd and the PWD are the
// same node then it trusts the PWD, so by setting it in the env for the child
// process we fix up all the paths returned by the go command.
cmd.Env = append(append([]string{}, env...), "PWD="+dir)
cmd.Dir = dir
cmd.Stdout = stdout
cmd.Stderr = stderr
if err := cmd.Run(); err != nil {
exitErr, ok := err.(*exec.ExitError)
if !ok {
// Catastrophic error:
// - executable not found
// - context cancellation
return nil, fmt.Errorf("couldn't exec 'go %v': %s %T", args, err, err)
}
// Export mode entails a build.
// If that build fails, errors appear on stderr
// (despite the -e flag) and the Export field is blank.
// Do not fail in that case.
if !usesExportData {
return nil, fmt.Errorf("go %v: %s: %s", args, exitErr, stderr)
}
}
// As of writing, go list -export prints some non-fatal compilation
// errors to stderr, even with -e set. We would prefer that it put
// them in the Package.Error JSON (see https://golang.org/issue/26319).
// In the meantime, there's nowhere good to put them, but they can
// be useful for debugging. Print them if $GOPACKAGESPRINTGOLISTERRORS
// is set.
if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTGOLISTERRORS") != "" {
fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(env, args...), stderr)
}
// debugging
if false {
fmt.Fprintf(os.Stderr, "%s stdout: <<%s>>\n", cmdDebugStr(env, args...), stdout)
}
return stdout, nil
}
func cmdDebugStr(envlist []string, args ...string) string {
env := make(map[string]string)
for _, kv := range envlist {
split := strings.Split(kv, "=")
k, v := split[0], split[1]
env[k] = v
}
return fmt.Sprintf("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %v", env["GOROOT"], env["GOPATH"], env["GO111MODULE"], env["PWD"], args)
}

View File

@@ -0,0 +1,222 @@
// 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 packages loads Go packages for inspection and analysis.
The Load function takes as input a list of patterns and return a list of Package
structs describing individual packages matched by those patterns.
The LoadMode controls the amount of detail in the loaded packages.
Load passes most patterns directly to the underlying build tool,
but all patterns with the prefix "query=", where query is a
non-empty string of letters from [a-z], are reserved and may be
interpreted as query operators.
Two query operators are currently supported: "file" and "pattern".
The query "file=path/to/file.go" matches the package or packages enclosing
the Go source file path/to/file.go. For example "file=~/go/src/fmt/print.go"
might return the packages "fmt" and "fmt [fmt.test]".
The query "pattern=string" causes "string" to be passed directly to
the underlying build tool. In most cases this is unnecessary,
but an application can use Load("pattern=" + x) as an escaping mechanism
to ensure that x is not interpreted as a query operator if it contains '='.
All other query operators are reserved for future use and currently
cause Load to report an error.
The Package struct provides basic information about the package, including
- ID, a unique identifier for the package in the returned set;
- GoFiles, the names of the package's Go source files;
- Imports, a map from source import strings to the Packages they name;
- Types, the type information for the package's exported symbols;
- Syntax, the parsed syntax trees for the package's source code; and
- TypeInfo, the result of a complete type-check of the package syntax trees.
(See the documentation for type Package for the complete list of fields
and more detailed descriptions.)
For example,
Load(nil, "bytes", "unicode...")
returns four Package structs describing the standard library packages
bytes, unicode, unicode/utf16, and unicode/utf8. Note that one pattern
can match multiple packages and that a package might be matched by
multiple patterns: in general it is not possible to determine which
packages correspond to which patterns.
Note that the list returned by Load contains only the packages matched
by the patterns. Their dependencies can be found by walking the import
graph using the Imports fields.
The Load function can be configured by passing a pointer to a Config as
the first argument. A nil Config is equivalent to the zero Config, which
causes Load to run in LoadFiles mode, collecting minimal information.
See the documentation for type Config for details.
As noted earlier, the Config.Mode controls the amount of detail
reported about the loaded packages, with each mode returning all the data of the
previous mode with some extra added. See the documentation for type LoadMode
for details.
Most tools should pass their command-line arguments (after any flags)
uninterpreted to the loader, so that the loader can interpret them
according to the conventions of the underlying build system.
See the Example function for typical usage.
*/
package packages // import "golang.org/x/tools/go/packages"
/*
Motivation and design considerations
The new package's design solves problems addressed by two existing
packages: go/build, which locates and describes packages, and
golang.org/x/tools/go/loader, which loads, parses and type-checks them.
The go/build.Package structure encodes too much of the 'go build' way
of organizing projects, leaving us in need of a data type that describes a
package of Go source code independent of the underlying build system.
We wanted something that works equally well with go build and vgo, and
also other build systems such as Bazel and Blaze, making it possible to
construct analysis tools that work in all these environments.
Tools such as errcheck and staticcheck were essentially unavailable to
the Go community at Google, and some of Google's internal tools for Go
are unavailable externally.
This new package provides a uniform way to obtain package metadata by
querying each of these build systems, optionally supporting their
preferred command-line notations for packages, so that tools integrate
neatly with users' build environments. The Metadata query function
executes an external query tool appropriate to the current workspace.
Loading packages always returns the complete import graph "all the way down",
even if all you want is information about a single package, because the query
mechanisms of all the build systems we currently support ({go,vgo} list, and
blaze/bazel aspect-based query) cannot provide detailed information
about one package without visiting all its dependencies too, so there is
no additional asymptotic cost to providing transitive information.
(This property might not be true of a hypothetical 5th build system.)
In calls to TypeCheck, all initial packages, and any package that
transitively depends on one of them, must be loaded from source.
Consider A->B->C->D->E: if A,C are initial, A,B,C must be loaded from
source; D may be loaded from export data, and E may not be loaded at all
(though it's possible that D's export data mentions it, so a
types.Package may be created for it and exposed.)
The old loader had a feature to suppress type-checking of function
bodies on a per-package basis, primarily intended to reduce the work of
obtaining type information for imported packages. Now that imports are
satisfied by export data, the optimization no longer seems necessary.
Despite some early attempts, the old loader did not exploit export data,
instead always using the equivalent of WholeProgram mode. This was due
to the complexity of mixing source and export data packages (now
resolved by the upward traversal mentioned above), and because export data
files were nearly always missing or stale. Now that 'go build' supports
caching, all the underlying build systems can guarantee to produce
export data in a reasonable (amortized) time.
Test "main" packages synthesized by the build system are now reported as
first-class packages, avoiding the need for clients (such as go/ssa) to
reinvent this generation logic.
One way in which go/packages is simpler than the old loader is in its
treatment of in-package tests. In-package tests are packages that
consist of all the files of the library under test, plus the test files.
The old loader constructed in-package tests by a two-phase process of
mutation called "augmentation": first it would construct and type check
all the ordinary library packages and type-check the packages that
depend on them; then it would add more (test) files to the package and
type-check again. This two-phase approach had four major problems:
1) in processing the tests, the loader modified the library package,
leaving no way for a client application to see both the test
package and the library package; one would mutate into the other.
2) because test files can declare additional methods on types defined in
the library portion of the package, the dispatch of method calls in
the library portion was affected by the presence of the test files.
This should have been a clue that the packages were logically
different.
3) this model of "augmentation" assumed at most one in-package test
per library package, which is true of projects using 'go build',
but not other build systems.
4) because of the two-phase nature of test processing, all packages that
import the library package had to be processed before augmentation,
forcing a "one-shot" API and preventing the client from calling Load
in several times in sequence as is now possible in WholeProgram mode.
(TypeCheck mode has a similar one-shot restriction for a different reason.)
Early drafts of this package supported "multi-shot" operation.
Although it allowed clients to make a sequence of calls (or concurrent
calls) to Load, building up the graph of Packages incrementally,
it was of marginal value: it complicated the API
(since it allowed some options to vary across calls but not others),
it complicated the implementation,
it cannot be made to work in Types mode, as explained above,
and it was less efficient than making one combined call (when this is possible).
Among the clients we have inspected, none made multiple calls to load
but could not be easily and satisfactorily modified to make only a single call.
However, applications changes may be required.
For example, the ssadump command loads the user-specified packages
and in addition the runtime package. It is tempting to simply append
"runtime" to the user-provided list, but that does not work if the user
specified an ad-hoc package such as [a.go b.go].
Instead, ssadump no longer requests the runtime package,
but seeks it among the dependencies of the user-specified packages,
and emits an error if it is not found.
Overlays: The Overlay field in the Config allows providing alternate contents
for Go source files, by providing a mapping from file path to contents.
go/packages will pull in new imports added in overlay files when go/packages
is run in LoadImports mode or greater.
Overlay support for the go list driver isn't complete yet: if the file doesn't
exist on disk, it will only be recognized in an overlay if it is a non-test file
and the package would be reported even without the overlay.
Questions & Tasks
- Add GOARCH/GOOS?
They are not portable concepts, but could be made portable.
Our goal has been to allow users to express themselves using the conventions
of the underlying build system: if the build system honors GOARCH
during a build and during a metadata query, then so should
applications built atop that query mechanism.
Conversely, if the target architecture of the build is determined by
command-line flags, the application can pass the relevant
flags through to the build system using a command such as:
myapp -query_flag="--cpu=amd64" -query_flag="--os=darwin"
However, this approach is low-level, unwieldy, and non-portable.
GOOS and GOARCH seem important enough to warrant a dedicated option.
- How should we handle partial failures such as a mixture of good and
malformed patterns, existing and non-existent packages, successful and
failed builds, import failures, import cycles, and so on, in a call to
Load?
- Support bazel, blaze, and go1.10 list, not just go1.11 list.
- Handle (and test) various partial success cases, e.g.
a mixture of good packages and:
invalid patterns
nonexistent packages
empty packages
packages with malformed package or import declarations
unreadable files
import cycles
other parse errors
type errors
Make sure we record errors at the correct place in the graph.
- Missing packages among initial arguments are not reported.
Return bogus packages for them, like golist does.
- "undeclared name" errors (for example) are reported out of source file
order. I suspect this is due to the breadth-first resolution now used
by go/types. Is that a bug? Discuss with gri.
*/

Some files were not shown because too many files have changed in this diff Show More