Switch to using the dep tool and update all the dependencies
This commit is contained in:
parent
5135ff73cb
commit
98c2d2c41b
5321 changed files with 4483201 additions and 5922 deletions
227
vendor/google.golang.org/api/iterator/examples_test.go
generated
vendored
Normal file
227
vendor/google.golang.org/api/iterator/examples_test.go
generated
vendored
Normal file
|
@ -0,0 +1,227 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 iterator_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/iterator"
|
||||
)
|
||||
|
||||
var (
|
||||
client *Client
|
||||
ctx = context.Background()
|
||||
)
|
||||
|
||||
var pageTemplate = template.Must(template.New("").Parse(`
|
||||
<table>
|
||||
{{range .Entries}}
|
||||
<tr><td>{{.}}</td></tr>
|
||||
{{end}}
|
||||
</table>
|
||||
{{with .Next}}
|
||||
<a href="/entries?pageToken={{.}}">Next Page</a>
|
||||
{{end}}
|
||||
`))
|
||||
|
||||
// This example demonstrates how to use Pager to support
|
||||
// pagination on a web site.
|
||||
func Example_webHandler(w http.ResponseWriter, r *http.Request) {
|
||||
const pageSize = 25
|
||||
it := client.Items(ctx)
|
||||
var items []int
|
||||
pageToken, err := iterator.NewPager(it, pageSize, r.URL.Query().Get("pageToken")).NextPage(&items)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("getting next page: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
data := struct {
|
||||
Items []int
|
||||
Next string
|
||||
}{
|
||||
items,
|
||||
pageToken,
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
if err := pageTemplate.Execute(&buf, data); err != nil {
|
||||
http.Error(w, fmt.Sprintf("executing page template: %v", err), http.StatusInternalServerError)
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
if _, err := buf.WriteTo(w); err != nil {
|
||||
log.Printf("writing response: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// This example demonstrates how to use a Pager to page through an iterator in a loop.
|
||||
func Example_pageLoop() {
|
||||
// Find all primes up to 42, in pages of size 5.
|
||||
const max = 42
|
||||
const pageSize = 5
|
||||
p := iterator.NewPager(Primes(max), pageSize, "" /* start from the beginning */)
|
||||
for page := 0; ; page++ {
|
||||
var items []int
|
||||
pageToken, err := p.NextPage(&items)
|
||||
if err != nil {
|
||||
log.Fatalf("Iterator paging failed: %v", err)
|
||||
}
|
||||
fmt.Printf("Page %d: %v\n", page, items)
|
||||
if pageToken == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Output:
|
||||
// Page 0: [2 3 5 7 11]
|
||||
// Page 1: [13 17 19 23 29]
|
||||
// Page 2: [31 37 41]
|
||||
}
|
||||
|
||||
// The example demonstrates how to use a Pager to request a page from a given token.
|
||||
func Example_pageToken() {
|
||||
const pageSize = 5
|
||||
const pageToken = "1337"
|
||||
p := iterator.NewPager(Primes(0), pageSize, pageToken)
|
||||
|
||||
var items []int
|
||||
nextPage, err := p.NextPage(&items)
|
||||
if err != nil {
|
||||
log.Fatalf("Iterator paging failed: %v", err)
|
||||
}
|
||||
fmt.Printf("Primes: %v\nToken: %q\n", items, nextPage)
|
||||
// Output:
|
||||
// Primes: [1361 1367 1373 1381 1399]
|
||||
// Token: "1400"
|
||||
}
|
||||
|
||||
// This example demonstrates how to get exactly the items in the buffer, without
|
||||
// triggering an extra RPC.
|
||||
func Example_serverPages() {
|
||||
// The iterator returned by Primes has a default page size of 20, which means
|
||||
// it will return all the primes in the range [2, 21).
|
||||
it := Primes(0)
|
||||
var items []int
|
||||
for {
|
||||
item, err := it.Next()
|
||||
if err != nil && err != iterator.Done {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err == iterator.Done {
|
||||
break
|
||||
}
|
||||
items = append(items, item)
|
||||
if it.PageInfo().Remaining() == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println(items)
|
||||
// Output:
|
||||
// [2 3 5 7 11 13 17 19]
|
||||
}
|
||||
|
||||
// Primes returns a iterator which returns a sequence of prime numbers.
|
||||
// If non-zero, max specifies the maximum number which could possibly be
|
||||
// returned.
|
||||
func Primes(max int) *SieveIterator {
|
||||
it := &SieveIterator{pos: 2, max: max}
|
||||
it.pageInfo, it.nextFunc = iterator.NewPageInfo(
|
||||
it.fetch,
|
||||
func() int { return len(it.items) },
|
||||
func() interface{} { b := it.items; it.items = nil; return b })
|
||||
return it
|
||||
}
|
||||
|
||||
// SieveIterator is an iterator that returns primes using the sieve of
|
||||
// Eratosthenes. It is a demonstration of how an iterator might work.
|
||||
// Internally, it uses "page size" as the number of ints to consider,
|
||||
// and "page token" as the first number to consider (defaults to 2).
|
||||
type SieveIterator struct {
|
||||
pageInfo *iterator.PageInfo
|
||||
nextFunc func() error
|
||||
max int // The largest number to consider.
|
||||
p []int // Primes in the range [2, pos).
|
||||
pos int // Next number to consider when generating p.
|
||||
items []int
|
||||
}
|
||||
|
||||
// PageInfo returns a PageInfo, which supports pagination.
|
||||
func (it *SieveIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
|
||||
|
||||
func (it *SieveIterator) fetch(pageSize int, pageToken string) (string, error) {
|
||||
start := 2
|
||||
if pageToken != "" {
|
||||
s, err := strconv.Atoi(pageToken)
|
||||
if err != nil || s < 2 {
|
||||
return "", fmt.Errorf("invalid token %q", pageToken)
|
||||
}
|
||||
start = s
|
||||
}
|
||||
if pageSize == 0 {
|
||||
pageSize = 20 // Default page size.
|
||||
}
|
||||
|
||||
// Make sure sufficient primes have been calculated.
|
||||
it.calc(start + pageSize)
|
||||
|
||||
// Find the subslice of primes which match this page.
|
||||
// Note that PageInfo requires that fetch does not remove any existing items,
|
||||
// so we cannot assume that items is empty at this call.
|
||||
items := it.p[sort.SearchInts(it.p, start):]
|
||||
items = items[:sort.SearchInts(items, start+pageSize)]
|
||||
it.items = append(it.items, items...)
|
||||
|
||||
if it.max > 0 && start+pageSize > it.max {
|
||||
return "", nil // No more possible numbers to return.
|
||||
}
|
||||
|
||||
return strconv.Itoa(start + pageSize), nil
|
||||
}
|
||||
|
||||
// calc populates p with all primes up to, but not including, max.
|
||||
func (it *SieveIterator) calc(max int) {
|
||||
if it.max > 0 && max > it.max+1 { // it.max is an inclusive bounds, max is exclusive.
|
||||
max = it.max + 1
|
||||
}
|
||||
outer:
|
||||
for x := it.pos; x < max; x++ {
|
||||
sqrt := int(math.Sqrt(float64(x)))
|
||||
for _, p := range it.p {
|
||||
switch {
|
||||
case x%p == 0:
|
||||
// Not a prime.
|
||||
continue outer
|
||||
case p > sqrt:
|
||||
// Only need to check up to sqrt.
|
||||
break
|
||||
}
|
||||
}
|
||||
it.p = append(it.p, x)
|
||||
}
|
||||
it.pos = max
|
||||
}
|
||||
|
||||
func (it *SieveIterator) Next() (int, error) {
|
||||
if err := it.nextFunc(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
item := it.items[0]
|
||||
it.items = it.items[1:]
|
||||
return item, nil
|
||||
}
|
231
vendor/google.golang.org/api/iterator/iterator.go
generated
vendored
Normal file
231
vendor/google.golang.org/api/iterator/iterator.go
generated
vendored
Normal file
|
@ -0,0 +1,231 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 iterator provides support for standard Google API iterators.
|
||||
// See https://github.com/GoogleCloudPlatform/gcloud-golang/wiki/Iterator-Guidelines.
|
||||
package iterator
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Done is returned by an iterator's Next method when the iteration is
|
||||
// complete; when there are no more items to return.
|
||||
var Done = errors.New("no more items in iterator")
|
||||
|
||||
// We don't support mixed calls to Next and NextPage because they play
|
||||
// with the paging state in incompatible ways.
|
||||
var errMixed = errors.New("iterator: Next and NextPage called on same iterator")
|
||||
|
||||
// PageInfo contains information about an iterator's paging state.
|
||||
type PageInfo struct {
|
||||
// Token is the token used to retrieve the next page of items from the
|
||||
// API. You may set Token immediately after creating an iterator to
|
||||
// begin iteration at a particular point. If Token is the empty string,
|
||||
// the iterator will begin with the first eligible item.
|
||||
//
|
||||
// The result of setting Token after the first call to Next is undefined.
|
||||
//
|
||||
// After the underlying API method is called to retrieve a page of items,
|
||||
// Token is set to the next-page token in the response.
|
||||
Token string
|
||||
|
||||
// MaxSize is the maximum number of items returned by a call to the API.
|
||||
// Set MaxSize as a hint to optimize the buffering behavior of the iterator.
|
||||
// If zero, the page size is determined by the underlying service.
|
||||
//
|
||||
// Use Pager to retrieve a page of a specific, exact size.
|
||||
MaxSize int
|
||||
|
||||
// The error state of the iterator. Manipulated by PageInfo.next and Pager.
|
||||
// This is a latch: it starts as nil, and once set should never change.
|
||||
err error
|
||||
|
||||
// If true, no more calls to fetch should be made. Set to true when fetch
|
||||
// returns an empty page token. The iterator is Done when this is true AND
|
||||
// the buffer is empty.
|
||||
atEnd bool
|
||||
|
||||
// Function that fetches a page from the underlying service. It should pass
|
||||
// the pageSize and pageToken arguments to the service, fill the buffer
|
||||
// with the results from the call, and return the next-page token returned
|
||||
// by the service. The function must not remove any existing items from the
|
||||
// buffer. If the underlying RPC takes an int32 page size, pageSize should
|
||||
// be silently truncated.
|
||||
fetch func(pageSize int, pageToken string) (nextPageToken string, err error)
|
||||
|
||||
// Function that clears the iterator's buffer, returning any currently buffered items.
|
||||
bufLen func() int
|
||||
|
||||
// Function that returns the buffer, after setting the buffer variable to nil.
|
||||
takeBuf func() interface{}
|
||||
|
||||
// Set to true on first call to PageInfo.next or Pager.NextPage. Used to check
|
||||
// for calls to both Next and NextPage with the same iterator.
|
||||
nextCalled, nextPageCalled bool
|
||||
}
|
||||
|
||||
// NewPageInfo exposes internals for iterator implementations.
|
||||
// It is not a stable interface.
|
||||
var NewPageInfo = newPageInfo
|
||||
|
||||
// If an iterator can support paging, its iterator-creating method should call
|
||||
// this (via the NewPageInfo variable above).
|
||||
//
|
||||
// The fetch, bufLen and takeBuf arguments provide access to the
|
||||
// iterator's internal slice of buffered items. They behave as described in
|
||||
// PageInfo, above.
|
||||
//
|
||||
// The return value is the PageInfo.next method bound to the returned PageInfo value.
|
||||
// (Returning it avoids exporting PageInfo.next.)
|
||||
func newPageInfo(fetch func(int, string) (string, error), bufLen func() int, takeBuf func() interface{}) (*PageInfo, func() error) {
|
||||
pi := &PageInfo{
|
||||
fetch: fetch,
|
||||
bufLen: bufLen,
|
||||
takeBuf: takeBuf,
|
||||
}
|
||||
return pi, pi.next
|
||||
}
|
||||
|
||||
// Remaining returns the number of items available before the iterator makes another API call.
|
||||
func (pi *PageInfo) Remaining() int { return pi.bufLen() }
|
||||
|
||||
// next provides support for an iterator's Next function. An iterator's Next
|
||||
// should return the error returned by next if non-nil; else it can assume
|
||||
// there is at least one item in its buffer, and it should return that item and
|
||||
// remove it from the buffer.
|
||||
func (pi *PageInfo) next() error {
|
||||
pi.nextCalled = true
|
||||
if pi.err != nil { // Once we get an error, always return it.
|
||||
// TODO(jba): fix so users can retry on transient errors? Probably not worth it.
|
||||
return pi.err
|
||||
}
|
||||
if pi.nextPageCalled {
|
||||
pi.err = errMixed
|
||||
return pi.err
|
||||
}
|
||||
// Loop until we get some items or reach the end.
|
||||
for pi.bufLen() == 0 && !pi.atEnd {
|
||||
if err := pi.fill(pi.MaxSize); err != nil {
|
||||
pi.err = err
|
||||
return pi.err
|
||||
}
|
||||
if pi.Token == "" {
|
||||
pi.atEnd = true
|
||||
}
|
||||
}
|
||||
// Either the buffer is non-empty or pi.atEnd is true (or both).
|
||||
if pi.bufLen() == 0 {
|
||||
// The buffer is empty and pi.atEnd is true, i.e. the service has no
|
||||
// more items.
|
||||
pi.err = Done
|
||||
}
|
||||
return pi.err
|
||||
}
|
||||
|
||||
// Call the service to fill the buffer, using size and pi.Token. Set pi.Token to the
|
||||
// next-page token returned by the call.
|
||||
// If fill returns a non-nil error, the buffer will be empty.
|
||||
func (pi *PageInfo) fill(size int) error {
|
||||
tok, err := pi.fetch(size, pi.Token)
|
||||
if err != nil {
|
||||
pi.takeBuf() // clear the buffer
|
||||
return err
|
||||
}
|
||||
pi.Token = tok
|
||||
return nil
|
||||
}
|
||||
|
||||
// Pageable is implemented by iterators that support paging.
|
||||
type Pageable interface {
|
||||
// PageInfo returns paging information associated with the iterator.
|
||||
PageInfo() *PageInfo
|
||||
}
|
||||
|
||||
// Pager supports retrieving iterator items a page at a time.
|
||||
type Pager struct {
|
||||
pageInfo *PageInfo
|
||||
pageSize int
|
||||
}
|
||||
|
||||
// NewPager returns a pager that uses iter. Calls to its NextPage method will
|
||||
// obtain exactly pageSize items, unless fewer remain. The pageToken argument
|
||||
// indicates where to start the iteration. Pass the empty string to start at
|
||||
// the beginning, or pass a token retrieved from a call to Pager.NextPage.
|
||||
//
|
||||
// If you use an iterator with a Pager, you must not call Next on the iterator.
|
||||
func NewPager(iter Pageable, pageSize int, pageToken string) *Pager {
|
||||
p := &Pager{
|
||||
pageInfo: iter.PageInfo(),
|
||||
pageSize: pageSize,
|
||||
}
|
||||
p.pageInfo.Token = pageToken
|
||||
if pageSize <= 0 {
|
||||
p.pageInfo.err = errors.New("iterator: page size must be positive")
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// NextPage retrieves a sequence of items from the iterator and appends them
|
||||
// to slicep, which must be a pointer to a slice of the iterator's item type.
|
||||
// Exactly p.pageSize items will be appended, unless fewer remain.
|
||||
//
|
||||
// The first return value is the page token to use for the next page of items.
|
||||
// If empty, there are no more pages. Aside from checking for the end of the
|
||||
// iteration, the returned page token is only needed if the iteration is to be
|
||||
// resumed a later time, in another context (possibly another process).
|
||||
//
|
||||
// The second return value is non-nil if an error occurred. It will never be
|
||||
// the special iterator sentinel value Done. To recognize the end of the
|
||||
// iteration, compare nextPageToken to the empty string.
|
||||
//
|
||||
// It is possible for NextPage to return a single zero-length page along with
|
||||
// an empty page token when there are no more items in the iteration.
|
||||
func (p *Pager) NextPage(slicep interface{}) (nextPageToken string, err error) {
|
||||
p.pageInfo.nextPageCalled = true
|
||||
if p.pageInfo.err != nil {
|
||||
return "", p.pageInfo.err
|
||||
}
|
||||
if p.pageInfo.nextCalled {
|
||||
p.pageInfo.err = errMixed
|
||||
return "", p.pageInfo.err
|
||||
}
|
||||
if p.pageInfo.bufLen() > 0 {
|
||||
return "", errors.New("must call NextPage with an empty buffer")
|
||||
}
|
||||
// The buffer must be empty here, so takeBuf is a no-op. We call it just to get
|
||||
// the buffer's type.
|
||||
wantSliceType := reflect.PtrTo(reflect.ValueOf(p.pageInfo.takeBuf()).Type())
|
||||
if slicep == nil {
|
||||
return "", errors.New("nil passed to Pager.NextPage")
|
||||
}
|
||||
vslicep := reflect.ValueOf(slicep)
|
||||
if vslicep.Type() != wantSliceType {
|
||||
return "", fmt.Errorf("slicep should be of type %s, got %T", wantSliceType, slicep)
|
||||
}
|
||||
for p.pageInfo.bufLen() < p.pageSize {
|
||||
if err := p.pageInfo.fill(p.pageSize - p.pageInfo.bufLen()); err != nil {
|
||||
p.pageInfo.err = err
|
||||
return "", p.pageInfo.err
|
||||
}
|
||||
if p.pageInfo.Token == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
e := vslicep.Elem()
|
||||
e.Set(reflect.AppendSlice(e, reflect.ValueOf(p.pageInfo.takeBuf())))
|
||||
return p.pageInfo.Token, nil
|
||||
}
|
270
vendor/google.golang.org/api/iterator/iterator_test.go
generated
vendored
Normal file
270
vendor/google.golang.org/api/iterator/iterator_test.go
generated
vendored
Normal file
|
@ -0,0 +1,270 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 iterator_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"google.golang.org/api/iterator"
|
||||
itest "google.golang.org/api/iterator/testing"
|
||||
)
|
||||
|
||||
// Service represents the implementation of a Google API's List method.
|
||||
// We want to test against a large range of possible valid behaviors.
|
||||
// All the behaviors this can generate are valid under the spec for
|
||||
// Google API paging.
|
||||
type service struct {
|
||||
// End of the sequence. end-1 is the last value returned.
|
||||
end int
|
||||
// Maximum number of items to return in one RPC. Also the default page size.
|
||||
// If zero, max is unlimited.
|
||||
max int
|
||||
// If true, return two empty pages before each RPC that returns items, and
|
||||
// two zero pages at the end. E.g. if end = 5, max = 2 and the pageSize
|
||||
// parameter to List is zero, then the number of items returned in
|
||||
// successive RPCS is:
|
||||
// 0 0 2 0 0 2 0 0 1 0 0
|
||||
// Note that this implies that the RPC returning the last items will have a
|
||||
// non-empty page token.
|
||||
zeroes bool
|
||||
}
|
||||
|
||||
// List simulates an API List RPC. It returns integers in the range [0, s.end).
|
||||
func (s *service) List(pageSize int, pageToken string) ([]int, string, error) {
|
||||
max := s.max
|
||||
if max == 0 {
|
||||
max = math.MaxInt64
|
||||
}
|
||||
// Never give back any more than s.max.
|
||||
if pageSize <= 0 || pageSize > max {
|
||||
pageSize = max
|
||||
}
|
||||
state := &listState{}
|
||||
if pageToken != "" {
|
||||
if err := json.Unmarshal([]byte(pageToken), state); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
ints := state.advance(pageSize, s.end, s.zeroes)
|
||||
if state.Start == s.end && (!s.zeroes || state.NumZeroes == 2) {
|
||||
pageToken = ""
|
||||
} else {
|
||||
bytes, err := json.Marshal(state)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
pageToken = string(bytes)
|
||||
}
|
||||
return ints, pageToken, nil
|
||||
}
|
||||
|
||||
type listState struct {
|
||||
Start int // where to start this page
|
||||
NumZeroes int // number of consecutive empty pages before this
|
||||
}
|
||||
|
||||
func (s *listState) advance(pageSize, end int, zeroes bool) []int {
|
||||
var page []int
|
||||
if zeroes && s.NumZeroes != 2 {
|
||||
// Return a zero page.
|
||||
} else {
|
||||
for i := s.Start; i < end && len(page) < pageSize; i++ {
|
||||
page = append(page, i)
|
||||
}
|
||||
}
|
||||
s.Start += len(page)
|
||||
if len(page) == 0 {
|
||||
s.NumZeroes++
|
||||
} else {
|
||||
s.NumZeroes = 0
|
||||
}
|
||||
return page
|
||||
}
|
||||
|
||||
func TestServiceList(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
svc service
|
||||
pageSize int
|
||||
want [][]int
|
||||
}{
|
||||
{service{end: 0}, 0, [][]int{nil}},
|
||||
{service{end: 5}, 0, [][]int{{0, 1, 2, 3, 4}}},
|
||||
{service{end: 5}, 8, [][]int{{0, 1, 2, 3, 4}}},
|
||||
{service{end: 5}, 2, [][]int{{0, 1}, {2, 3}, {4}}},
|
||||
{service{end: 5, max: 2}, 0, [][]int{{0, 1}, {2, 3}, {4}}},
|
||||
{service{end: 5, max: 2}, 1, [][]int{{0}, {1}, {2}, {3}, {4}}},
|
||||
{service{end: 5, max: 2}, 10, [][]int{{0, 1}, {2, 3}, {4}}},
|
||||
{service{end: 5, zeroes: true}, 0, [][]int{nil, nil, {0, 1, 2, 3, 4}, nil, nil}},
|
||||
{service{end: 5, max: 3, zeroes: true}, 0, [][]int{nil, nil, {0, 1, 2}, nil, nil, {3, 4}, nil, nil}},
|
||||
} {
|
||||
var got [][]int
|
||||
token := ""
|
||||
for {
|
||||
items, nextToken, err := test.svc.List(test.pageSize, token)
|
||||
if err != nil {
|
||||
t.Fatalf("%v, %d: %v", test.svc, test.pageSize, err)
|
||||
}
|
||||
got = append(got, items)
|
||||
if nextToken == "" {
|
||||
break
|
||||
}
|
||||
token = nextToken
|
||||
}
|
||||
if !reflect.DeepEqual(got, test.want) {
|
||||
t.Errorf("%v, %d: got %v, want %v", test.svc, test.pageSize, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type Client struct{ s *service }
|
||||
|
||||
// ItemIterator is a sample implementation of a standard iterator.
|
||||
type ItemIterator struct {
|
||||
pageInfo *iterator.PageInfo
|
||||
nextFunc func() error
|
||||
s *service
|
||||
items []int
|
||||
}
|
||||
|
||||
// PageInfo returns a PageInfo, which supports pagination.
|
||||
func (it *ItemIterator) PageInfo() *iterator.PageInfo { return it.pageInfo }
|
||||
|
||||
// Items is a sample implementation of an iterator-creating method.
|
||||
func (c *Client) Items(ctx context.Context) *ItemIterator {
|
||||
it := &ItemIterator{s: c.s}
|
||||
it.pageInfo, it.nextFunc = iterator.NewPageInfo(
|
||||
it.fetch,
|
||||
func() int { return len(it.items) },
|
||||
func() interface{} { b := it.items; it.items = nil; return b })
|
||||
return it
|
||||
}
|
||||
|
||||
func (it *ItemIterator) fetch(pageSize int, pageToken string) (string, error) {
|
||||
items, tok, err := it.s.List(pageSize, pageToken)
|
||||
it.items = append(it.items, items...)
|
||||
return tok, err
|
||||
}
|
||||
|
||||
func (it *ItemIterator) Next() (int, error) {
|
||||
if err := it.nextFunc(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
item := it.items[0]
|
||||
it.items = it.items[1:]
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func TestNext(t *testing.T) {
|
||||
// Test the iterator's Next method with a variety of different service behaviors.
|
||||
// This is primarily a test of PageInfo.next.
|
||||
for _, svc := range []service{
|
||||
{end: 0},
|
||||
{end: 5},
|
||||
{end: 5, max: 1},
|
||||
{end: 5, max: 2},
|
||||
{end: 5, zeroes: true},
|
||||
{end: 5, max: 2, zeroes: true},
|
||||
} {
|
||||
client := &Client{&svc}
|
||||
|
||||
msg, ok := itest.TestIterator(
|
||||
seq(0, svc.end),
|
||||
func() interface{} { return client.Items(ctx) },
|
||||
func(it interface{}) (interface{}, error) { return it.(*ItemIterator).Next() })
|
||||
if !ok {
|
||||
t.Errorf("%+v: %s", svc, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(jba): test setting PageInfo.MaxSize
|
||||
// TODO(jba): test setting PageInfo.Token
|
||||
|
||||
// Verify that, for an iterator that uses PageInfo.next to implement its Next
|
||||
// method, using Next and NextPage together result in an error.
|
||||
func TestNextWithNextPage(t *testing.T) {
|
||||
client := &Client{&service{end: 11}}
|
||||
var items []int
|
||||
|
||||
// Calling Next before NextPage.
|
||||
it := client.Items(ctx)
|
||||
it.Next()
|
||||
_, err := iterator.NewPager(it, 1, "").NextPage(&items)
|
||||
if err == nil {
|
||||
t.Error("NextPage after Next: got nil, want error")
|
||||
}
|
||||
_, err = it.Next()
|
||||
if err == nil {
|
||||
t.Error("Next after NextPage: got nil, want error")
|
||||
}
|
||||
|
||||
// Next between two calls to NextPage.
|
||||
it = client.Items(ctx)
|
||||
p := iterator.NewPager(it, 1, "")
|
||||
p.NextPage(&items)
|
||||
_, err = it.Next()
|
||||
if err == nil {
|
||||
t.Error("Next after NextPage: got nil, want error")
|
||||
}
|
||||
_, err = p.NextPage(&items)
|
||||
if err == nil {
|
||||
t.Error("second NextPage after Next: got nil, want error")
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that we turn various potential reflection panics into errors.
|
||||
func TestNextPageReflectionErrors(t *testing.T) {
|
||||
client := &Client{&service{end: 1}}
|
||||
p := iterator.NewPager(client.Items(ctx), 1, "")
|
||||
|
||||
// Passing the nil interface value.
|
||||
_, err := p.NextPage(nil)
|
||||
if err == nil {
|
||||
t.Error("nil: got nil, want error")
|
||||
}
|
||||
|
||||
// Passing a non-slice.
|
||||
_, err = p.NextPage(17)
|
||||
if err == nil {
|
||||
t.Error("non-slice: got nil, want error")
|
||||
}
|
||||
|
||||
// Passing a slice of the wrong type.
|
||||
var bools []bool
|
||||
_, err = p.NextPage(&bools)
|
||||
if err == nil {
|
||||
t.Error("wrong type: got nil, want error")
|
||||
}
|
||||
|
||||
// Using a slice of the right type, but not passing a pointer to it.
|
||||
var ints []int
|
||||
_, err = p.NextPage(ints)
|
||||
if err == nil {
|
||||
t.Error("not a pointer: got nil, want error")
|
||||
}
|
||||
}
|
||||
|
||||
// seq returns a slice containing the values in [from, to).
|
||||
func seq(from, to int) []int {
|
||||
var r []int
|
||||
for i := from; i < to; i++ {
|
||||
r = append(r, i)
|
||||
}
|
||||
return r
|
||||
}
|
187
vendor/google.golang.org/api/iterator/testing/testing.go
generated
vendored
Normal file
187
vendor/google.golang.org/api/iterator/testing/testing.go
generated
vendored
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2016 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 testing provides support functions for testing iterators conforming
|
||||
// to the standard pattern.
|
||||
// See package google.golang.org/api/iterator and
|
||||
// https://github.com/GoogleCloudPlatform/gcloud-golang/wiki/Iterator-Guidelines.
|
||||
package testing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"google.golang.org/api/iterator"
|
||||
)
|
||||
|
||||
// TestIterator tests the Next method of a standard iterator. It assumes that
|
||||
// the underlying sequence to be iterated over already exists.
|
||||
//
|
||||
// The want argument should be a slice that contains the elements of this
|
||||
// sequence. It may be an empty slice, but it must not be the nil interface
|
||||
// value. The elements must be comparable with reflect.DeepEqual.
|
||||
//
|
||||
// The create function should create and return a new iterator.
|
||||
// It will typically look like
|
||||
// func() interface{} { return client.Items(ctx) }
|
||||
//
|
||||
// The next function takes the return value of create and should return the
|
||||
// result of calling Next on the iterator. It can usually be defined as
|
||||
// func(it interface{}) (interface{}, error) { return it.(*ItemIterator).Next() }
|
||||
//
|
||||
// TestIterator checks that the iterator returns all the elements of want
|
||||
// in order, followed by (zero, done). It also confirms that subsequent calls
|
||||
// to next also return (zero, done).
|
||||
//
|
||||
// If the iterator implements the method
|
||||
// PageInfo() *iterator.PageInfo
|
||||
// then exact pagination with iterator.Pager is also tested. Pagination testing
|
||||
// will be more informative if the want slice contains at least three elements.
|
||||
//
|
||||
// On success, TestIterator returns ("", true). On failure, it returns a
|
||||
// suitable error message and false.
|
||||
func TestIterator(want interface{}, create func() interface{}, next func(interface{}) (interface{}, error)) (string, bool) {
|
||||
vWant := reflect.ValueOf(want)
|
||||
if vWant.Kind() != reflect.Slice {
|
||||
return "'want' must be a slice", false
|
||||
}
|
||||
it := create()
|
||||
msg, ok := testNext(vWant, it, next)
|
||||
if !ok {
|
||||
return msg, ok
|
||||
}
|
||||
if _, ok := it.(iterator.Pageable); !ok || vWant.Len() == 0 {
|
||||
return "", true
|
||||
}
|
||||
return testPaging(vWant, create, next)
|
||||
}
|
||||
|
||||
// Check that the iterator returns vWant, the desired sequence.
|
||||
func testNext(vWant reflect.Value, it interface{}, next func(interface{}) (interface{}, error)) (string, bool) {
|
||||
for i := 0; i < vWant.Len(); i++ {
|
||||
got, err := next(it)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("#%d: got %v, expected an item", i, err), false
|
||||
}
|
||||
w := vWant.Index(i).Interface()
|
||||
if !reflect.DeepEqual(got, w) {
|
||||
return fmt.Sprintf("#%d: got %+v, want %+v", i, got, w), false
|
||||
}
|
||||
}
|
||||
// We now should see (<zero value of item type>, done), no matter how many
|
||||
// additional calls we make.
|
||||
zero := reflect.Zero(vWant.Type().Elem()).Interface()
|
||||
for i := 0; i < 3; i++ {
|
||||
got, err := next(it)
|
||||
if err != iterator.Done {
|
||||
return fmt.Sprintf("at end: got error %v, want iterator.Done", err), false
|
||||
}
|
||||
// Since err == iterator.Done, got should be zero.
|
||||
if got != zero {
|
||||
return fmt.Sprintf("got %+v with done, want zero %T", got, zero), false
|
||||
}
|
||||
}
|
||||
return "", true
|
||||
}
|
||||
|
||||
// Test the iterator's behavior when used with iterator.Pager.
|
||||
func testPaging(vWant reflect.Value, create func() interface{}, next func(interface{}) (interface{}, error)) (string, bool) {
|
||||
// Test page sizes that are smaller, equal to, and greater than the length
|
||||
// of the expected sequence.
|
||||
for _, pageSize := range []int{1, 2, vWant.Len(), vWant.Len() + 10} {
|
||||
wantPages := wantedPages(vWant, pageSize)
|
||||
// Test the Pager in two ways.
|
||||
// First, by creating a single Pager and calling NextPage in a loop,
|
||||
// ignoring the page token except for detecting the end of the
|
||||
// iteration.
|
||||
it := create().(iterator.Pageable)
|
||||
pager := iterator.NewPager(it, pageSize, "")
|
||||
msg, ok := testPager(fmt.Sprintf("ignore page token, pageSize %d", pageSize),
|
||||
vWant.Type(), wantPages,
|
||||
func(_ string, pagep interface{}) (string, error) {
|
||||
return pager.NextPage(pagep)
|
||||
})
|
||||
if !ok {
|
||||
return msg, false
|
||||
}
|
||||
// Second, by creating a new Pager for each page, passing in the page
|
||||
// token from the previous page, as would be done in a web handler.
|
||||
it = create().(iterator.Pageable)
|
||||
msg, ok = testPager(fmt.Sprintf("use page token, pageSize %d", pageSize),
|
||||
vWant.Type(), wantPages,
|
||||
func(pageToken string, pagep interface{}) (string, error) {
|
||||
return iterator.NewPager(it, pageSize, pageToken).NextPage(pagep)
|
||||
})
|
||||
if !ok {
|
||||
return msg, false
|
||||
}
|
||||
}
|
||||
return "", true
|
||||
}
|
||||
|
||||
// Create the pages we expect to see.
|
||||
func wantedPages(vWant reflect.Value, pageSize int) []interface{} {
|
||||
var pages []interface{}
|
||||
for i, j := 0, pageSize; i < vWant.Len(); i, j = j, j+pageSize {
|
||||
if j > vWant.Len() {
|
||||
j = vWant.Len()
|
||||
}
|
||||
pages = append(pages, vWant.Slice(i, j).Interface())
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
func testPager(prefix string, sliceType reflect.Type, wantPages []interface{},
|
||||
nextPage func(pageToken string, pagep interface{}) (string, error)) (string, bool) {
|
||||
tok := ""
|
||||
var err error
|
||||
for i := 0; i < len(wantPages)+1; i++ {
|
||||
vpagep := reflect.New(sliceType)
|
||||
tok, err = nextPage(tok, vpagep.Interface())
|
||||
if err != nil {
|
||||
return fmt.Sprintf("%s, page #%d: got error %v", prefix, i, err), false
|
||||
}
|
||||
if i == len(wantPages) {
|
||||
// Allow one empty page at the end.
|
||||
if vpagep.Elem().Len() != 0 || tok != "" {
|
||||
return fmt.Sprintf("%s: did not get one empty page at end", prefix), false
|
||||
}
|
||||
break
|
||||
}
|
||||
if msg, ok := compareSlices(vpagep.Elem(), reflect.ValueOf(wantPages[i])); !ok {
|
||||
return fmt.Sprintf("%s, page #%d:\n%s", prefix, i, msg), false
|
||||
}
|
||||
if tok == "" {
|
||||
if i != len(wantPages)-1 {
|
||||
return fmt.Sprintf("%s, page #%d: got empty page token", prefix, i), false
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return "", true
|
||||
}
|
||||
|
||||
// Compare two slices element-by-element. If they are equal, return ("", true).
|
||||
// Otherwise, return a description of the difference and false.
|
||||
func compareSlices(vgot, vwant reflect.Value) (string, bool) {
|
||||
if got, want := vgot.Len(), vwant.Len(); got != want {
|
||||
return fmt.Sprintf("got %d items, want %d", got, want), false
|
||||
}
|
||||
for i := 0; i < vgot.Len(); i++ {
|
||||
if got, want := vgot.Index(i).Interface(), vwant.Index(i).Interface(); !reflect.DeepEqual(got, want) {
|
||||
return fmt.Sprintf("got[%d] = %+v\nwant = %+v", i, got, want), false
|
||||
}
|
||||
}
|
||||
return "", true
|
||||
}
|
39
vendor/google.golang.org/api/iterator/testing/testing_test.go
generated
vendored
Normal file
39
vendor/google.golang.org/api/iterator/testing/testing_test.go
generated
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
// 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 testing
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCompareSlices(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
a, b []int
|
||||
wantEqual bool
|
||||
}{
|
||||
{nil, nil, true},
|
||||
{nil, []int{}, true},
|
||||
{[]int{1, 2}, []int{1, 2}, true},
|
||||
{[]int{1}, []int{1, 2}, false},
|
||||
{[]int{1, 2}, []int{1}, false},
|
||||
{[]int{1, 2}, []int{1, 3}, false},
|
||||
} {
|
||||
_, got := compareSlices(reflect.ValueOf(test.a), reflect.ValueOf(test.b))
|
||||
if got != test.wantEqual {
|
||||
t.Errorf("%v, %v: got %t, want %t", test.a, test.b, got, test.wantEqual)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue