浏览代码

Vendoring shakers library and update go-check

The shakers library defines a bunch of go-check checkers to ease
writing tests.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Vincent Demeester 9 年之前
父节点
当前提交
9685b4767f

+ 2 - 1
hack/vendor.sh

@@ -9,7 +9,7 @@ source 'hack/.vendor-helpers.sh'
 clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe
 clone git github.com/Sirupsen/logrus v0.8.2 # logrus is a common dependency among multiple deps
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
-clone git github.com/go-check/check 64131543e7896d5bcc6bd5a76287eb75ea96c673
+clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1
 clone git github.com/gorilla/context 14f550f51a
 clone git github.com/gorilla/mux e444e69cbd
 clone git github.com/kr/pty 5cf931ef8f
@@ -17,6 +17,7 @@ clone git github.com/mattn/go-sqlite3 v1.1.0
 clone git github.com/microsoft/hcsshim 7f646aa6b26bcf90caee91e93cde4a80d0d8a83e
 clone git github.com/mistifyio/go-zfs v2.1.1
 clone git github.com/tchap/go-patricia v2.1.0
+clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
 
 #get libnetwork packages

+ 24 - 37
pkg/integration/checker/checker.go

@@ -2,17 +2,14 @@
 package checker
 
 import (
-	"fmt"
-	"strings"
-
 	"github.com/go-check/check"
+	"github.com/vdemeester/shakers"
 )
 
 // As a commodity, we bring all check.Checker variables into the current namespace to avoid having
 // to think about check.X versus checker.X.
 var (
 	DeepEquals   = check.DeepEquals
-	Equals       = check.Equals
 	ErrorMatches = check.ErrorMatches
 	FitsTypeOf   = check.FitsTypeOf
 	HasLen       = check.HasLen
@@ -23,37 +20,27 @@ var (
 	NotNil       = check.NotNil
 	PanicMatches = check.PanicMatches
 	Panics       = check.Panics
-)
-
-// Contains checker verifies that string value contains a substring.
-var Contains check.Checker = &containsChecker{
-	&check.CheckerInfo{
-		Name:   "Contains",
-		Params: []string{"value", "substring"},
-	},
-}
 
-type containsChecker struct {
-	*check.CheckerInfo
-}
-
-func (checker *containsChecker) Check(params []interface{}, names []string) (bool, string) {
-	return contains(params[0], params[1])
-}
-
-func contains(value, substring interface{}) (bool, string) {
-	substringStr, ok := substring.(string)
-	if !ok {
-		return false, "Substring must be a string"
-	}
-	valueStr, valueIsStr := value.(string)
-	if !valueIsStr {
-		if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr {
-			valueStr, valueIsStr = valueWithStr.String(), true
-		}
-	}
-	if valueIsStr {
-		return strings.Contains(valueStr, substringStr), ""
-	}
-	return false, "Obtained value is not a string and has no .String()"
-}
+	Contains           = shakers.Contains
+	ContainsAny        = shakers.ContainsAny
+	Count              = shakers.Count
+	Equals             = shakers.Equals
+	EqualFold          = shakers.EqualFold
+	False              = shakers.False
+	GreaterOrEqualThan = shakers.GreaterOrEqualThan
+	GreaterThan        = shakers.GreaterThan
+	HasPrefix          = shakers.HasPrefix
+	HasSuffix          = shakers.HasSuffix
+	Index              = shakers.Index
+	IndexAny           = shakers.IndexAny
+	IsAfter            = shakers.IsAfter
+	IsBefore           = shakers.IsBefore
+	IsBetween          = shakers.IsBetween
+	IsLower            = shakers.IsLower
+	IsUpper            = shakers.IsUpper
+	LessOrEqualThan    = shakers.LessOrEqualThan
+	LessThan           = shakers.LessThan
+	TimeEquals         = shakers.TimeEquals
+	True               = shakers.True
+	TimeIgnore         = shakers.TimeIgnore
+)

+ 0 - 57
pkg/integration/checker/checker_test.go

@@ -1,57 +0,0 @@
-package checker
-
-import (
-	"reflect"
-	"testing"
-
-	"github.com/go-check/check"
-)
-
-func Test(t *testing.T) {
-	check.TestingT(t)
-}
-
-func init() {
-	check.Suite(&CheckersS{})
-}
-
-type CheckersS struct{}
-
-var _ = check.Suite(&CheckersS{})
-
-func testInfo(c *check.C, checker check.Checker, name string, paramNames []string) {
-	info := checker.Info()
-	if info.Name != name {
-		c.Fatalf("Got name %s, expected %s", info.Name, name)
-	}
-	if !reflect.DeepEqual(info.Params, paramNames) {
-		c.Fatalf("Got param names %#v, expected %#v", info.Params, paramNames)
-	}
-}
-
-func testCheck(c *check.C, checker check.Checker, expectedResult bool, expectedError string, params ...interface{}) ([]interface{}, []string) {
-	info := checker.Info()
-	if len(params) != len(info.Params) {
-		c.Fatalf("unexpected param count in test; expected %d got %d", len(info.Params), len(params))
-	}
-	names := append([]string{}, info.Params...)
-	result, error := checker.Check(params, names)
-	if result != expectedResult || error != expectedError {
-		c.Fatalf("%s.Check(%#v) returned (%#v, %#v) rather than (%#v, %#v)",
-			info.Name, params, result, error, expectedResult, expectedError)
-	}
-	return params, names
-}
-
-func (s *CheckersS) TestContains(c *check.C) {
-	testInfo(c, Contains, "Contains", []string{"value", "substring"})
-
-	testCheck(c, Contains, true, "", "abcd", "bc")
-	testCheck(c, Contains, false, "", "abcd", "efg")
-	testCheck(c, Contains, false, "", "", "bc")
-	testCheck(c, Contains, true, "", "abcd", "")
-	testCheck(c, Contains, true, "", "", "")
-
-	testCheck(c, Contains, false, "Obtained value is not a string and has no .String()", 12, "1")
-	testCheck(c, Contains, false, "Substring must be a string", "", 1)
-}

+ 27 - 3
vendor/src/github.com/go-check/check/benchmark.go

@@ -1,6 +1,30 @@
-// Copyright 2009 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.
+// Copyright (c) 2012 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.
 
 package check
 

+ 31 - 22
vendor/src/github.com/go-check/check/check.go

@@ -21,6 +21,7 @@ import (
 	"strconv"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
@@ -43,7 +44,7 @@ const (
 	missedSt
 )
 
-type funcStatus int
+type funcStatus uint32
 
 // A method value can't reach its own Method structure.
 type methodType struct {
@@ -81,7 +82,7 @@ type C struct {
 	method    *methodType
 	kind      funcKind
 	testName  string
-	status    funcStatus
+	_status   funcStatus
 	logb      *logger
 	logw      io.Writer
 	done      chan *C
@@ -93,6 +94,14 @@ type C struct {
 	timer
 }
 
+func (c *C) status() funcStatus {
+	return funcStatus(atomic.LoadUint32((*uint32)(&c._status)))
+}
+
+func (c *C) setStatus(s funcStatus) {
+	atomic.StoreUint32((*uint32)(&c._status), uint32(s))
+}
+
 func (c *C) stopNow() {
 	runtime.Goexit()
 }
@@ -326,7 +335,7 @@ func (c *C) logPanic(skip int, value interface{}) {
 			if name == "Value.call" && strings.HasSuffix(path, valueGo) {
 				continue
 			}
-			if name == "call16" && strings.Contains(path, asmGo) {
+			if (name == "call16" || name == "call32") && strings.Contains(path, asmGo) {
 				continue
 			}
 			c.logf("%s:%d\n  in %s", nicePath(file), line, name)
@@ -455,7 +464,7 @@ func (tracker *resultTracker) _loopRoutine() {
 				tracker._waiting += 1
 			case c = <-tracker._doneChan:
 				tracker._waiting -= 1
-				switch c.status {
+				switch c.status() {
 				case succeededSt:
 					if c.kind == testKd {
 						if c.mustFail {
@@ -601,15 +610,15 @@ func (runner *suiteRunner) run() *Result {
 		runner.tracker.start()
 		if runner.checkFixtureArgs() {
 			c := runner.runFixture(runner.setUpSuite, "", nil)
-			if c == nil || c.status == succeededSt {
+			if c == nil || c.status() == succeededSt {
 				for i := 0; i != len(runner.tests); i++ {
 					c := runner.runTest(runner.tests[i])
-					if c.status == fixturePanickedSt {
+					if c.status() == fixturePanickedSt {
 						runner.skipTests(missedSt, runner.tests[i+1:])
 						break
 					}
 				}
-			} else if c != nil && c.status == skippedSt {
+			} else if c != nil && c.status() == skippedSt {
 				runner.skipTests(skippedSt, runner.tests)
 			} else {
 				runner.skipTests(missedSt, runner.tests)
@@ -674,22 +683,22 @@ func (runner *suiteRunner) callDone(c *C) {
 		switch v := value.(type) {
 		case *fixturePanic:
 			if v.status == skippedSt {
-				c.status = skippedSt
+				c.setStatus(skippedSt)
 			} else {
 				c.logSoftPanic("Fixture has panicked (see related PANIC)")
-				c.status = fixturePanickedSt
+				c.setStatus(fixturePanickedSt)
 			}
 		default:
 			c.logPanic(1, value)
-			c.status = panickedSt
+			c.setStatus(panickedSt)
 		}
 	}
 	if c.mustFail {
-		switch c.status {
+		switch c.status() {
 		case failedSt:
-			c.status = succeededSt
+			c.setStatus(succeededSt)
 		case succeededSt:
-			c.status = failedSt
+			c.setStatus(failedSt)
 			c.logString("Error: Test succeeded, but was expected to fail")
 			c.logString("Reason: " + c.reason)
 		}
@@ -724,11 +733,11 @@ func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName stri
 		return nil
 	}
 	c := runner.runFixture(method, testName, logb)
-	if c != nil && c.status != succeededSt {
+	if c != nil && c.status() != succeededSt {
 		if skipped != nil {
-			*skipped = c.status == skippedSt
+			*skipped = c.status() == skippedSt
 		}
-		panic(&fixturePanic{c.status, method})
+		panic(&fixturePanic{c.status(), method})
 	}
 	return c
 }
@@ -753,7 +762,7 @@ func (runner *suiteRunner) forkTest(method *methodType) *C {
 			if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
 				// Rather than a plain panic, provide a more helpful message when
 				// the argument type is incorrect.
-				c.status = panickedSt
+				c.setStatus(panickedSt)
 				c.logArgPanic(c.method, "*check.C")
 				return
 			}
@@ -773,7 +782,7 @@ func (runner *suiteRunner) forkTest(method *methodType) *C {
 			c.StartTimer()
 			c.method.Call([]reflect.Value{reflect.ValueOf(c)})
 			c.StopTimer()
-			if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
+			if c.status() != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
 				return
 			}
 			perOpN := int(1e9)
@@ -808,7 +817,7 @@ func (runner *suiteRunner) runTest(method *methodType) *C {
 func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) {
 	for _, method := range methods {
 		runner.runFunc(method, testKd, "", nil, func(c *C) {
-			c.status = status
+			c.setStatus(status)
 		})
 	}
 }
@@ -825,7 +834,7 @@ func (runner *suiteRunner) checkFixtureArgs() bool {
 				succeeded = false
 				runner.runFunc(method, fixtureKd, "", nil, func(c *C) {
 					c.logArgPanic(method, "*check.C")
-					c.status = panickedSt
+					c.setStatus(panickedSt)
 				})
 			}
 		}
@@ -839,7 +848,7 @@ func (runner *suiteRunner) reportCallStarted(c *C) {
 
 func (runner *suiteRunner) reportCallDone(c *C) {
 	runner.tracker.callDone(c)
-	switch c.status {
+	switch c.status() {
 	case succeededSt:
 		if c.mustFail {
 			runner.output.WriteCallSuccess("FAIL EXPECTED", c)
@@ -917,7 +926,7 @@ func (ow *outputWriter) WriteCallSuccess(label string, c *C) {
 		if c.reason != "" {
 			suffix = " (" + c.reason + ")"
 		}
-		if c.status == succeededSt {
+		if c.status() == succeededSt {
 			suffix += "\t" + c.timerString()
 		}
 		suffix += "\n"

+ 4 - 4
vendor/src/github.com/go-check/check/helpers.go

@@ -16,7 +16,7 @@ func (c *C) TestName() string {
 
 // Failed returns whether the currently running test has already failed.
 func (c *C) Failed() bool {
-	return c.status == failedSt
+	return c.status() == failedSt
 }
 
 // Fail marks the currently running test as failed.
@@ -25,7 +25,7 @@ func (c *C) Failed() bool {
 // what went wrong. The higher level helper functions will fail the test
 // and do the logging properly.
 func (c *C) Fail() {
-	c.status = failedSt
+	c.setStatus(failedSt)
 }
 
 // FailNow marks the currently running test as failed and stops running it.
@@ -40,7 +40,7 @@ func (c *C) FailNow() {
 // Succeed marks the currently running test as succeeded, undoing any
 // previous failures.
 func (c *C) Succeed() {
-	c.status = succeededSt
+	c.setStatus(succeededSt)
 }
 
 // SucceedNow marks the currently running test as succeeded, undoing any
@@ -72,7 +72,7 @@ func (c *C) Skip(reason string) {
 		panic("Missing reason why the test is being skipped")
 	}
 	c.reason = reason
-	c.status = skippedSt
+	c.setStatus(skippedSt)
 	c.stopNow()
 }
 

+ 4 - 0
vendor/src/github.com/vdemeester/shakers/.gitignore

@@ -0,0 +1,4 @@
+Godeps/_workspace/bin
+Godeps/_workspace/pkg
+
+*.test

+ 12 - 0
vendor/src/github.com/vdemeester/shakers/Dockerfile

@@ -0,0 +1,12 @@
+FROM golang:1.5
+
+RUN go get golang.org/x/tools/cmd/cover
+RUN go get github.com/golang/lint/golint
+RUN go get golang.org/x/tools/cmd/vet
+
+WORKDIR /go/src/github.com/vdemeester/shakers
+
+# enable GO15VENDOREXPERIMENT
+ENV GO15VENDOREXPERIMENT 1
+
+COPY . /go/src/github.com/vdemeester/shakers

+ 40 - 0
vendor/src/github.com/vdemeester/shakers/Makefile

@@ -0,0 +1,40 @@
+.PHONY: all
+
+SHAKERS_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/vdemeester/shakers/$(BIND_DIR)")
+
+GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
+SHAKERS_DEV_IMAGE := shakers-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH))
+
+DOCKER_RUN_SHAKERS := docker run $(if $(CIRCLECI),,--rm) -it $(SHAKERS_ENVS) $(SHAKERS_MOUNT) "$(SHAKERS_DEV_IMAGE)"
+
+print-%: ; @echo $*=$($*)
+
+default: binary
+
+binary: build
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh binary
+
+test-unit: build
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh test-unit
+
+validate: build
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-gofmt validate-golint validate-govet
+
+validate-govet: build
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-govet
+
+validate-golint: build
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-golint
+
+validate-gofmt: build
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-gofmt
+
+build:
+	docker build -t "$(SHAKERS_DEV_IMAGE)" .
+
+shell: build
+	$(DOCKER_RUN_SHAKERS) /bin/bash
+
+run-dev:
+	go build
+	./traefik

+ 24 - 0
vendor/src/github.com/vdemeester/shakers/README.md

@@ -0,0 +1,24 @@
+# Shakers
+🐹 + 🐙 = 😽 [![Circle CI](https://circleci.com/gh/vdemeester/shakers.svg?style=svg)](https://circleci.com/gh/vdemeester/shakers)
+
+A collection of `go-check` Checkers to ease the use of it.
+
+## Building and testing it
+
+You need either [docker](https://github.com/docker/docker), or `go`
+and `godep` in order to build and test shakers.
+
+### Using Docker and Makefile
+
+You need to run the ``test-unit`` target. 
+```bash
+$ make test-unit
+docker build -t "shakers-dev:master" .
+# […]
+docker run --rm -it   "shakers-dev:master" ./script/make.sh test-unit
+---> Making bundle: test-unit (in .)
++ go test -cover -coverprofile=cover.out .
+ok      github.com/vdemeester/shakers   0.015s  coverage: 96.0% of statements
+
+Test success
+```

+ 46 - 0
vendor/src/github.com/vdemeester/shakers/bool.go

@@ -0,0 +1,46 @@
+package shakers
+
+import (
+	"github.com/go-check/check"
+)
+
+// True checker verifies the obtained value is true
+//
+//    c.Assert(myBool, True)
+//
+var True check.Checker = &boolChecker{
+	&check.CheckerInfo{
+		Name:   "True",
+		Params: []string{"obtained"},
+	},
+	true,
+}
+
+// False checker verifies the obtained value is false
+//
+//    c.Assert(myBool, False)
+//
+var False check.Checker = &boolChecker{
+	&check.CheckerInfo{
+		Name:   "False",
+		Params: []string{"obtained"},
+	},
+	false,
+}
+
+type boolChecker struct {
+	*check.CheckerInfo
+	expected bool
+}
+
+func (checker *boolChecker) Check(params []interface{}, names []string) (bool, string) {
+	return is(checker.expected, params[0])
+}
+
+func is(expected bool, obtained interface{}) (bool, string) {
+	obtainedBool, ok := obtained.(bool)
+	if !ok {
+		return false, "obtained value must be a bool."
+	}
+	return obtainedBool == expected, ""
+}

+ 11 - 0
vendor/src/github.com/vdemeester/shakers/circle.yml

@@ -0,0 +1,11 @@
+machine:
+  services:
+    - docker
+
+dependencies:
+  override:
+    - make validate
+
+test:
+  override:
+    - make test-unit

+ 310 - 0
vendor/src/github.com/vdemeester/shakers/common.go

@@ -0,0 +1,310 @@
+package shakers
+
+import (
+	"reflect"
+	"time"
+
+	"github.com/go-check/check"
+)
+
+// As a commodity, we bring all check.Checker variables into the current namespace to avoid having
+// to think about check.X versus checker.X.
+var (
+	DeepEquals   = check.DeepEquals
+	ErrorMatches = check.ErrorMatches
+	FitsTypeOf   = check.FitsTypeOf
+	HasLen       = check.HasLen
+	Implements   = check.Implements
+	IsNil        = check.IsNil
+	Matches      = check.Matches
+	Not          = check.Not
+	NotNil       = check.NotNil
+	PanicMatches = check.PanicMatches
+	Panics       = check.Panics
+)
+
+// Equaler is an interface implemented if the type has a Equal method.
+// This is used to compare struct using shakers.Equals.
+type Equaler interface {
+	Equal(Equaler) bool
+}
+
+// Equals checker verifies the obtained value is equal to the specified one.
+// It's is smart in a wait that it supports several *types* (built-in, Equaler,
+// time.Time)
+//
+//    c.Assert(myStruct, Equals, aStruct, check.Commentf("bouuuhh"))
+//    c.Assert(myTime, Equals, aTime, check.Commentf("bouuuhh"))
+//
+var Equals check.Checker = &equalChecker{
+	&check.CheckerInfo{
+		Name:   "Equals",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type equalChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *equalChecker) Check(params []interface{}, names []string) (bool, string) {
+	return isEqual(params[0], params[1])
+}
+
+func isEqual(obtained, expected interface{}) (bool, string) {
+	switch obtained.(type) {
+	case time.Time:
+		return timeEquals(obtained, expected)
+	case Equaler:
+		return equalerEquals(obtained, expected)
+	default:
+		if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
+			return false, "obtained value and expected value have not the same type."
+		}
+		return obtained == expected, ""
+	}
+}
+
+func equalerEquals(obtained, expected interface{}) (bool, string) {
+	expectedEqualer, ok := expected.(Equaler)
+	if !ok {
+		return false, "expected value must be an Equaler - implementing Equal(Equaler)."
+	}
+	obtainedEqualer, ok := obtained.(Equaler)
+	if !ok {
+		return false, "obtained value must be an Equaler - implementing Equal(Equaler)."
+	}
+	return obtainedEqualer.Equal(expectedEqualer), ""
+}
+
+// GreaterThan checker verifies the obtained value is greater than the specified one.
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
+//
+//    c.Assert(myTime, GreaterThan, aTime, check.Commentf("bouuuhh"))
+//    c.Assert(myInt, GreaterThan, 2, check.Commentf("bouuuhh"))
+//
+var GreaterThan check.Checker = &greaterThanChecker{
+	&check.CheckerInfo{
+		Name:   "GreaterThan",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type greaterThanChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *greaterThanChecker) Check(params []interface{}, names []string) (bool, string) {
+	return greaterThan(params[0], params[1])
+}
+
+func greaterThan(obtained, expected interface{}) (bool, string) {
+	if _, ok := obtained.(time.Time); ok {
+		return isAfter(obtained, expected)
+	}
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
+		return false, "obtained value and expected value have not the same type."
+	}
+	switch v := obtained.(type) {
+	case float32:
+		return v > expected.(float32), ""
+	case float64:
+		return v > expected.(float64), ""
+	case int:
+		return v > expected.(int), ""
+	case int8:
+		return v > expected.(int8), ""
+	case int16:
+		return v > expected.(int16), ""
+	case int32:
+		return v > expected.(int32), ""
+	case int64:
+		return v > expected.(int64), ""
+	case uint:
+		return v > expected.(uint), ""
+	case uint8:
+		return v > expected.(uint8), ""
+	case uint16:
+		return v > expected.(uint16), ""
+	case uint32:
+		return v > expected.(uint32), ""
+	case uint64:
+		return v > expected.(uint64), ""
+	default:
+		return false, "obtained value type not supported."
+	}
+}
+
+// GreaterOrEqualThan checker verifies the obtained value is greater or equal than the specified one.
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
+//
+//    c.Assert(myTime, GreaterOrEqualThan, aTime, check.Commentf("bouuuhh"))
+//    c.Assert(myInt, GreaterOrEqualThan, 2, check.Commentf("bouuuhh"))
+//
+var GreaterOrEqualThan check.Checker = &greaterOrEqualThanChecker{
+	&check.CheckerInfo{
+		Name:   "GreaterOrEqualThan",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type greaterOrEqualThanChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *greaterOrEqualThanChecker) Check(params []interface{}, names []string) (bool, string) {
+	return greaterOrEqualThan(params[0], params[1])
+}
+
+func greaterOrEqualThan(obtained, expected interface{}) (bool, string) {
+	if _, ok := obtained.(time.Time); ok {
+		return isAfter(obtained, expected)
+	}
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
+		return false, "obtained value and expected value have not the same type."
+	}
+	switch v := obtained.(type) {
+	case float32:
+		return v >= expected.(float32), ""
+	case float64:
+		return v >= expected.(float64), ""
+	case int:
+		return v >= expected.(int), ""
+	case int8:
+		return v >= expected.(int8), ""
+	case int16:
+		return v >= expected.(int16), ""
+	case int32:
+		return v >= expected.(int32), ""
+	case int64:
+		return v >= expected.(int64), ""
+	case uint:
+		return v >= expected.(uint), ""
+	case uint8:
+		return v >= expected.(uint8), ""
+	case uint16:
+		return v >= expected.(uint16), ""
+	case uint32:
+		return v >= expected.(uint32), ""
+	case uint64:
+		return v >= expected.(uint64), ""
+	default:
+		return false, "obtained value type not supported."
+	}
+}
+
+// LessThan checker verifies the obtained value is less than the specified one.
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
+//
+//    c.Assert(myTime, LessThan, aTime, check.Commentf("bouuuhh"))
+//    c.Assert(myInt, LessThan, 2, check.Commentf("bouuuhh"))
+//
+var LessThan check.Checker = &lessThanChecker{
+	&check.CheckerInfo{
+		Name:   "LessThan",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type lessThanChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *lessThanChecker) Check(params []interface{}, names []string) (bool, string) {
+	return lessThan(params[0], params[1])
+}
+
+func lessThan(obtained, expected interface{}) (bool, string) {
+	if _, ok := obtained.(time.Time); ok {
+		return isBefore(obtained, expected)
+	}
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
+		return false, "obtained value and expected value have not the same type."
+	}
+	switch v := obtained.(type) {
+	case float32:
+		return v < expected.(float32), ""
+	case float64:
+		return v < expected.(float64), ""
+	case int:
+		return v < expected.(int), ""
+	case int8:
+		return v < expected.(int8), ""
+	case int16:
+		return v < expected.(int16), ""
+	case int32:
+		return v < expected.(int32), ""
+	case int64:
+		return v < expected.(int64), ""
+	case uint:
+		return v < expected.(uint), ""
+	case uint8:
+		return v < expected.(uint8), ""
+	case uint16:
+		return v < expected.(uint16), ""
+	case uint32:
+		return v < expected.(uint32), ""
+	case uint64:
+		return v < expected.(uint64), ""
+	default:
+		return false, "obtained value type not supported."
+	}
+}
+
+// LessOrEqualThan checker verifies the obtained value is less or equal than the specified one.
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
+//
+//    c.Assert(myTime, LessThan, aTime, check.Commentf("bouuuhh"))
+//    c.Assert(myInt, LessThan, 2, check.Commentf("bouuuhh"))
+//
+var LessOrEqualThan check.Checker = &lessOrEqualThanChecker{
+	&check.CheckerInfo{
+		Name:   "LessOrEqualThan",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type lessOrEqualThanChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *lessOrEqualThanChecker) Check(params []interface{}, names []string) (bool, string) {
+	return lessOrEqualThan(params[0], params[1])
+}
+
+func lessOrEqualThan(obtained, expected interface{}) (bool, string) {
+	if _, ok := obtained.(time.Time); ok {
+		return isBefore(obtained, expected)
+	}
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
+		return false, "obtained value and expected value have not the same type."
+	}
+	switch v := obtained.(type) {
+	case float32:
+		return v <= expected.(float32), ""
+	case float64:
+		return v <= expected.(float64), ""
+	case int:
+		return v <= expected.(int), ""
+	case int8:
+		return v <= expected.(int8), ""
+	case int16:
+		return v <= expected.(int16), ""
+	case int32:
+		return v <= expected.(int32), ""
+	case int64:
+		return v <= expected.(int64), ""
+	case uint:
+		return v <= expected.(uint), ""
+	case uint8:
+		return v <= expected.(uint8), ""
+	case uint16:
+		return v <= expected.(uint16), ""
+	case uint32:
+		return v <= expected.(uint32), ""
+	case uint64:
+		return v <= expected.(uint64), ""
+	default:
+		return false, "obtained value type not supported."
+	}
+}

+ 4 - 0
vendor/src/github.com/vdemeester/shakers/glide.yaml

@@ -0,0 +1,4 @@
+package: main
+import:
+  - package: github.com/go-check/check
+    ref:     11d3bc7aa68e238947792f30573146a3231fc0f1

+ 168 - 0
vendor/src/github.com/vdemeester/shakers/string.go

@@ -0,0 +1,168 @@
+// Package shakers provide some checker implementation the go-check.Checker interface.
+package shakers
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/go-check/check"
+)
+
+// Contains checker verifies that obtained value contains a substring.
+var Contains check.Checker = &substringChecker{
+	&check.CheckerInfo{
+		Name:   "Contains",
+		Params: []string{"obtained", "substring"},
+	},
+	strings.Contains,
+}
+
+// ContainsAny checker verifies that any Unicode code points in chars
+// are in the obtained string.
+var ContainsAny check.Checker = &substringChecker{
+	&check.CheckerInfo{
+		Name:   "ContainsAny",
+		Params: []string{"obtained", "chars"},
+	},
+	strings.ContainsAny,
+}
+
+// HasPrefix checker verifies that obtained value has the specified substring as prefix
+var HasPrefix check.Checker = &substringChecker{
+	&check.CheckerInfo{
+		Name:   "HasPrefix",
+		Params: []string{"obtained", "prefix"},
+	},
+	strings.HasPrefix,
+}
+
+// HasSuffix checker verifies that obtained value has the specified substring as prefix
+var HasSuffix check.Checker = &substringChecker{
+	&check.CheckerInfo{
+		Name:   "HasSuffix",
+		Params: []string{"obtained", "suffix"},
+	},
+	strings.HasSuffix,
+}
+
+// EqualFold checker verifies that obtained value is, interpreted as UTF-8 strings, are equal under Unicode case-folding.
+var EqualFold check.Checker = &substringChecker{
+	&check.CheckerInfo{
+		Name:   "EqualFold",
+		Params: []string{"obtained", "expected"},
+	},
+	strings.EqualFold,
+}
+
+type substringChecker struct {
+	*check.CheckerInfo
+	substringFunction func(string, string) bool
+}
+
+func (checker *substringChecker) Check(params []interface{}, names []string) (bool, string) {
+	obtained := params[0]
+	substring := params[1]
+	substringStr, ok := substring.(string)
+	if !ok {
+		return false, fmt.Sprintf("%s value must be a string.", names[1])
+	}
+	obtainedString, obtainedIsStr := obtained.(string)
+	if !obtainedIsStr {
+		if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer {
+			obtainedString, obtainedIsStr = obtainedWithStringer.String(), true
+		}
+	}
+	if obtainedIsStr {
+		return checker.substringFunction(obtainedString, substringStr), ""
+	}
+	return false, "obtained value is not a string and has no .String()."
+}
+
+// IndexAny checker verifies that the index of the first instance of any Unicode code point from chars in the obtained value is equal to expected
+var IndexAny check.Checker = &substringCountChecker{
+	&check.CheckerInfo{
+		Name:   "IndexAny",
+		Params: []string{"obtained", "chars", "expected"},
+	},
+	strings.IndexAny,
+}
+
+// Index checker verifies that the index of the first instance of sep in the obtained value is equal to expected
+var Index check.Checker = &substringCountChecker{
+	&check.CheckerInfo{
+		Name:   "Index",
+		Params: []string{"obtained", "sep", "expected"},
+	},
+	strings.Index,
+}
+
+// Count checker verifies that obtained value has the specified number of non-overlapping instances of sep
+var Count check.Checker = &substringCountChecker{
+	&check.CheckerInfo{
+		Name:   "Count",
+		Params: []string{"obtained", "sep", "expected"},
+	},
+	strings.Count,
+}
+
+type substringCountChecker struct {
+	*check.CheckerInfo
+	substringFunction func(string, string) int
+}
+
+func (checker *substringCountChecker) Check(params []interface{}, names []string) (bool, string) {
+	obtained := params[0]
+	substring := params[1]
+	expected := params[2]
+	substringStr, ok := substring.(string)
+	if !ok {
+		return false, fmt.Sprintf("%s value must be a string.", names[1])
+	}
+	obtainedString, obtainedIsStr := obtained.(string)
+	if !obtainedIsStr {
+		if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer {
+			obtainedString, obtainedIsStr = obtainedWithStringer.String(), true
+		}
+	}
+	if obtainedIsStr {
+		return checker.substringFunction(obtainedString, substringStr) == expected, ""
+	}
+	return false, "obtained value is not a string and has no .String()."
+}
+
+// IsLower checker verifies that the obtained value is in lower case
+var IsLower check.Checker = &stringTransformChecker{
+	&check.CheckerInfo{
+		Name:   "IsLower",
+		Params: []string{"obtained"},
+	},
+	strings.ToLower,
+}
+
+// IsUpper checker verifies that the obtained value is in lower case
+var IsUpper check.Checker = &stringTransformChecker{
+	&check.CheckerInfo{
+		Name:   "IsUpper",
+		Params: []string{"obtained"},
+	},
+	strings.ToUpper,
+}
+
+type stringTransformChecker struct {
+	*check.CheckerInfo
+	stringFunction func(string) string
+}
+
+func (checker *stringTransformChecker) Check(params []interface{}, names []string) (bool, string) {
+	obtained := params[0]
+	obtainedString, obtainedIsStr := obtained.(string)
+	if !obtainedIsStr {
+		if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer {
+			obtainedString, obtainedIsStr = obtainedWithStringer.String(), true
+		}
+	}
+	if obtainedIsStr {
+		return checker.stringFunction(obtainedString) == obtainedString, ""
+	}
+	return false, "obtained value is not a string and has no .String()."
+}

+ 234 - 0
vendor/src/github.com/vdemeester/shakers/time.go

@@ -0,0 +1,234 @@
+package shakers
+
+import (
+	"fmt"
+	"time"
+
+	"github.com/go-check/check"
+)
+
+// Default format when parsing (in addition to RFC and default time formats..)
+const shortForm = "2006-01-02"
+
+// IsBefore checker verifies the specified value is before the specified time.
+// It is exclusive.
+//
+//    c.Assert(myTime, IsBefore, theTime, check.Commentf("bouuuhhh"))
+//
+var IsBefore check.Checker = &isBeforeChecker{
+	&check.CheckerInfo{
+		Name:   "IsBefore",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type isBeforeChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *isBeforeChecker) Check(params []interface{}, names []string) (bool, string) {
+	return isBefore(params[0], params[1])
+}
+
+func isBefore(value, t interface{}) (bool, string) {
+	tTime, ok := parseTime(t)
+	if !ok {
+		return false, "expected must be a Time struct, or parseable."
+	}
+	valueTime, valueIsTime := parseTime(value)
+	if valueIsTime {
+		return valueTime.Before(tTime), ""
+	}
+	return false, "obtained value is not a time.Time struct or parseable as a time."
+}
+
+// IsAfter checker verifies the specified value is before the specified time.
+// It is exclusive.
+//
+//    c.Assert(myTime, IsAfter, theTime, check.Commentf("bouuuhhh"))
+//
+var IsAfter check.Checker = &isAfterChecker{
+	&check.CheckerInfo{
+		Name:   "IsAfter",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type isAfterChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *isAfterChecker) Check(params []interface{}, names []string) (bool, string) {
+	return isAfter(params[0], params[1])
+}
+
+func isAfter(value, t interface{}) (bool, string) {
+	tTime, ok := parseTime(t)
+	if !ok {
+		return false, "expected must be a Time struct, or parseable."
+	}
+	valueTime, valueIsTime := parseTime(value)
+	if valueIsTime {
+		return valueTime.After(tTime), ""
+	}
+	return false, "obtained value is not a time.Time struct or parseable as a time."
+}
+
+// IsBetween checker verifies the specified time is between the specified start
+// and end. It's exclusive so if the specified time is at the tip of the interval.
+//
+//    c.Assert(myTime, IsBetween, startTime, endTime, check.Commentf("bouuuhhh"))
+//
+var IsBetween check.Checker = &isBetweenChecker{
+	&check.CheckerInfo{
+		Name:   "IsBetween",
+		Params: []string{"obtained", "start", "end"},
+	},
+}
+
+type isBetweenChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *isBetweenChecker) Check(params []interface{}, names []string) (bool, string) {
+	return isBetween(params[0], params[1], params[2])
+}
+
+func isBetween(value, start, end interface{}) (bool, string) {
+	startTime, ok := parseTime(start)
+	if !ok {
+		return false, "start must be a Time struct, or parseable."
+	}
+	endTime, ok := parseTime(end)
+	if !ok {
+		return false, "end must be a Time struct, or parseable."
+	}
+	valueTime, valueIsTime := parseTime(value)
+	if valueIsTime {
+		return valueTime.After(startTime) && valueTime.Before(endTime), ""
+	}
+	return false, "obtained value is not a time.Time struct or parseable as a time."
+}
+
+// TimeEquals checker verifies the specified time is the equal to the expected
+// time.
+//
+//    c.Assert(myTime, TimeEquals, expected, check.Commentf("bouhhh"))
+//
+// It's possible to ignore some part of the time (like hours, minutes, etc..) using
+// the TimeIgnore checker with it.
+//
+//    c.Assert(myTime, TimeIgnore(TimeEquals, time.Hour), expected, check.Commentf("... bouh.."))
+//
+var TimeEquals check.Checker = &timeEqualsChecker{
+	&check.CheckerInfo{
+		Name:   "TimeEquals",
+		Params: []string{"obtained", "expected"},
+	},
+}
+
+type timeEqualsChecker struct {
+	*check.CheckerInfo
+}
+
+func (checker *timeEqualsChecker) Check(params []interface{}, names []string) (bool, string) {
+	return timeEquals(params[0], params[1])
+}
+
+func timeEquals(obtained, expected interface{}) (bool, string) {
+	expectedTime, ok := parseTime(expected)
+	if !ok {
+		return false, "expected must be a Time struct, or parseable."
+	}
+	valueTime, valueIsTime := parseTime(obtained)
+	if valueIsTime {
+		return valueTime.Equal(expectedTime), ""
+	}
+	return false, "obtained value is not a time.Time struct or parseable as a time."
+}
+
+// TimeIgnore checker will ignore some part of the time on the encapsulated checker.
+//
+//    c.Assert(myTime, TimeIgnore(IsBetween, time.Second), start, end)
+//
+// FIXME use interface{} for ignore (to enable "Month", ..
+func TimeIgnore(checker check.Checker, ignore time.Duration) check.Checker {
+	return &timeIgnoreChecker{
+		sub:    checker,
+		ignore: ignore,
+	}
+}
+
+type timeIgnoreChecker struct {
+	sub    check.Checker
+	ignore time.Duration
+}
+
+func (checker *timeIgnoreChecker) Info() *check.CheckerInfo {
+	info := *checker.sub.Info()
+	info.Name = fmt.Sprintf("TimeIgnore(%s, %v)", info.Name, checker.ignore)
+	return &info
+}
+
+func (checker *timeIgnoreChecker) Check(params []interface{}, names []string) (bool, string) {
+	// Naive implementation : all params are supposed to be date
+	mParams := make([]interface{}, len(params))
+	for index, param := range params {
+		paramTime, ok := parseTime(param)
+		if !ok {
+			return false, fmt.Sprintf("%s must be a Time struct, or parseable.", names[index])
+		}
+		year := paramTime.Year()
+		month := paramTime.Month()
+		day := paramTime.Day()
+		hour := paramTime.Hour()
+		min := paramTime.Minute()
+		sec := paramTime.Second()
+		nsec := paramTime.Nanosecond()
+		location := paramTime.Location()
+		switch checker.ignore {
+		case time.Hour:
+			hour = 0
+			fallthrough
+		case time.Minute:
+			min = 0
+			fallthrough
+		case time.Second:
+			sec = 0
+			fallthrough
+		case time.Millisecond:
+			fallthrough
+		case time.Microsecond:
+			fallthrough
+		case time.Nanosecond:
+			nsec = 0
+		}
+		mParams[index] = time.Date(year, month, day, hour, min, sec, nsec, location)
+	}
+	return checker.sub.Check(mParams, names)
+}
+
+func parseTime(datetime interface{}) (time.Time, bool) {
+	switch datetime.(type) {
+	case time.Time:
+		return datetime.(time.Time), true
+	case string:
+		return parseTimeAsString(datetime.(string))
+	default:
+		if datetimeWithStr, ok := datetime.(fmt.Stringer); ok {
+			return parseTimeAsString(datetimeWithStr.String())
+		}
+		return time.Time{}, false
+	}
+}
+
+func parseTimeAsString(timeAsStr string) (time.Time, bool) {
+	forms := []string{shortForm, time.RFC3339, time.RFC3339Nano, time.RFC822, time.RFC822Z}
+	for _, form := range forms {
+		datetime, err := time.Parse(form, timeAsStr)
+		if err == nil {
+			return datetime, true
+		}
+	}
+	return time.Time{}, false
+}