Browse code

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 authored on 2015/10/17 20:41:44
Showing 16 changed files
... ...
@@ -9,7 +9,7 @@ source 'hack/.vendor-helpers.sh'
9 9
 clone git github.com/Azure/go-ansiterm 70b2c90b260171e829f1ebd7c17f600c11858dbe
10 10
 clone git github.com/Sirupsen/logrus v0.8.2 # logrus is a common dependency among multiple deps
11 11
 clone git github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
12
-clone git github.com/go-check/check 64131543e7896d5bcc6bd5a76287eb75ea96c673
12
+clone git github.com/go-check/check 11d3bc7aa68e238947792f30573146a3231fc0f1
13 13
 clone git github.com/gorilla/context 14f550f51a
14 14
 clone git github.com/gorilla/mux e444e69cbd
15 15
 clone git github.com/kr/pty 5cf931ef8f
... ...
@@ -17,6 +17,7 @@ clone git github.com/mattn/go-sqlite3 v1.1.0
17 17
 clone git github.com/microsoft/hcsshim 7f646aa6b26bcf90caee91e93cde4a80d0d8a83e
18 18
 clone git github.com/mistifyio/go-zfs v2.1.1
19 19
 clone git github.com/tchap/go-patricia v2.1.0
20
+clone git github.com/vdemeester/shakers 3c10293ce22b900c27acad7b28656196fcc2f73b
20 21
 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
21 22
 
22 23
 #get libnetwork packages
... ...
@@ -2,17 +2,14 @@
2 2
 package checker
3 3
 
4 4
 import (
5
-	"fmt"
6
-	"strings"
7
-
8 5
 	"github.com/go-check/check"
6
+	"github.com/vdemeester/shakers"
9 7
 )
10 8
 
11 9
 // As a commodity, we bring all check.Checker variables into the current namespace to avoid having
12 10
 // to think about check.X versus checker.X.
13 11
 var (
14 12
 	DeepEquals   = check.DeepEquals
15
-	Equals       = check.Equals
16 13
 	ErrorMatches = check.ErrorMatches
17 14
 	FitsTypeOf   = check.FitsTypeOf
18 15
 	HasLen       = check.HasLen
... ...
@@ -23,37 +20,27 @@ var (
23 23
 	NotNil       = check.NotNil
24 24
 	PanicMatches = check.PanicMatches
25 25
 	Panics       = check.Panics
26
-)
27
-
28
-// Contains checker verifies that string value contains a substring.
29
-var Contains check.Checker = &containsChecker{
30
-	&check.CheckerInfo{
31
-		Name:   "Contains",
32
-		Params: []string{"value", "substring"},
33
-	},
34
-}
35 26
 
36
-type containsChecker struct {
37
-	*check.CheckerInfo
38
-}
39
-
40
-func (checker *containsChecker) Check(params []interface{}, names []string) (bool, string) {
41
-	return contains(params[0], params[1])
42
-}
43
-
44
-func contains(value, substring interface{}) (bool, string) {
45
-	substringStr, ok := substring.(string)
46
-	if !ok {
47
-		return false, "Substring must be a string"
48
-	}
49
-	valueStr, valueIsStr := value.(string)
50
-	if !valueIsStr {
51
-		if valueWithStr, valueHasStr := value.(fmt.Stringer); valueHasStr {
52
-			valueStr, valueIsStr = valueWithStr.String(), true
53
-		}
54
-	}
55
-	if valueIsStr {
56
-		return strings.Contains(valueStr, substringStr), ""
57
-	}
58
-	return false, "Obtained value is not a string and has no .String()"
59
-}
27
+	Contains           = shakers.Contains
28
+	ContainsAny        = shakers.ContainsAny
29
+	Count              = shakers.Count
30
+	Equals             = shakers.Equals
31
+	EqualFold          = shakers.EqualFold
32
+	False              = shakers.False
33
+	GreaterOrEqualThan = shakers.GreaterOrEqualThan
34
+	GreaterThan        = shakers.GreaterThan
35
+	HasPrefix          = shakers.HasPrefix
36
+	HasSuffix          = shakers.HasSuffix
37
+	Index              = shakers.Index
38
+	IndexAny           = shakers.IndexAny
39
+	IsAfter            = shakers.IsAfter
40
+	IsBefore           = shakers.IsBefore
41
+	IsBetween          = shakers.IsBetween
42
+	IsLower            = shakers.IsLower
43
+	IsUpper            = shakers.IsUpper
44
+	LessOrEqualThan    = shakers.LessOrEqualThan
45
+	LessThan           = shakers.LessThan
46
+	TimeEquals         = shakers.TimeEquals
47
+	True               = shakers.True
48
+	TimeIgnore         = shakers.TimeIgnore
49
+)
60 50
deleted file mode 100644
... ...
@@ -1,57 +0,0 @@
1
-package checker
2
-
3
-import (
4
-	"reflect"
5
-	"testing"
6
-
7
-	"github.com/go-check/check"
8
-)
9
-
10
-func Test(t *testing.T) {
11
-	check.TestingT(t)
12
-}
13
-
14
-func init() {
15
-	check.Suite(&CheckersS{})
16
-}
17
-
18
-type CheckersS struct{}
19
-
20
-var _ = check.Suite(&CheckersS{})
21
-
22
-func testInfo(c *check.C, checker check.Checker, name string, paramNames []string) {
23
-	info := checker.Info()
24
-	if info.Name != name {
25
-		c.Fatalf("Got name %s, expected %s", info.Name, name)
26
-	}
27
-	if !reflect.DeepEqual(info.Params, paramNames) {
28
-		c.Fatalf("Got param names %#v, expected %#v", info.Params, paramNames)
29
-	}
30
-}
31
-
32
-func testCheck(c *check.C, checker check.Checker, expectedResult bool, expectedError string, params ...interface{}) ([]interface{}, []string) {
33
-	info := checker.Info()
34
-	if len(params) != len(info.Params) {
35
-		c.Fatalf("unexpected param count in test; expected %d got %d", len(info.Params), len(params))
36
-	}
37
-	names := append([]string{}, info.Params...)
38
-	result, error := checker.Check(params, names)
39
-	if result != expectedResult || error != expectedError {
40
-		c.Fatalf("%s.Check(%#v) returned (%#v, %#v) rather than (%#v, %#v)",
41
-			info.Name, params, result, error, expectedResult, expectedError)
42
-	}
43
-	return params, names
44
-}
45
-
46
-func (s *CheckersS) TestContains(c *check.C) {
47
-	testInfo(c, Contains, "Contains", []string{"value", "substring"})
48
-
49
-	testCheck(c, Contains, true, "", "abcd", "bc")
50
-	testCheck(c, Contains, false, "", "abcd", "efg")
51
-	testCheck(c, Contains, false, "", "", "bc")
52
-	testCheck(c, Contains, true, "", "abcd", "")
53
-	testCheck(c, Contains, true, "", "", "")
54
-
55
-	testCheck(c, Contains, false, "Obtained value is not a string and has no .String()", 12, "1")
56
-	testCheck(c, Contains, false, "Substring must be a string", "", 1)
57
-}
... ...
@@ -1,6 +1,30 @@
1
-// Copyright 2009 The Go Authors. All rights reserved.
2
-// Use of this source code is governed by a BSD-style
3
-// license that can be found in the LICENSE file.
1
+// Copyright (c) 2012 The Go Authors. All rights reserved.
2
+// 
3
+// Redistribution and use in source and binary forms, with or without
4
+// modification, are permitted provided that the following conditions are
5
+// met:
6
+// 
7
+//    * Redistributions of source code must retain the above copyright
8
+// notice, this list of conditions and the following disclaimer.
9
+//    * Redistributions in binary form must reproduce the above
10
+// copyright notice, this list of conditions and the following disclaimer
11
+// in the documentation and/or other materials provided with the
12
+// distribution.
13
+//    * Neither the name of Google Inc. nor the names of its
14
+// contributors may be used to endorse or promote products derived from
15
+// this software without specific prior written permission.
16
+// 
17
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4 28
 
5 29
 package check
6 30
 
... ...
@@ -21,6 +21,7 @@ import (
21 21
 	"strconv"
22 22
 	"strings"
23 23
 	"sync"
24
+	"sync/atomic"
24 25
 	"time"
25 26
 )
26 27
 
... ...
@@ -43,7 +44,7 @@ const (
43 43
 	missedSt
44 44
 )
45 45
 
46
-type funcStatus int
46
+type funcStatus uint32
47 47
 
48 48
 // A method value can't reach its own Method structure.
49 49
 type methodType struct {
... ...
@@ -81,7 +82,7 @@ type C struct {
81 81
 	method    *methodType
82 82
 	kind      funcKind
83 83
 	testName  string
84
-	status    funcStatus
84
+	_status   funcStatus
85 85
 	logb      *logger
86 86
 	logw      io.Writer
87 87
 	done      chan *C
... ...
@@ -93,6 +94,14 @@ type C struct {
93 93
 	timer
94 94
 }
95 95
 
96
+func (c *C) status() funcStatus {
97
+	return funcStatus(atomic.LoadUint32((*uint32)(&c._status)))
98
+}
99
+
100
+func (c *C) setStatus(s funcStatus) {
101
+	atomic.StoreUint32((*uint32)(&c._status), uint32(s))
102
+}
103
+
96 104
 func (c *C) stopNow() {
97 105
 	runtime.Goexit()
98 106
 }
... ...
@@ -326,7 +335,7 @@ func (c *C) logPanic(skip int, value interface{}) {
326 326
 			if name == "Value.call" && strings.HasSuffix(path, valueGo) {
327 327
 				continue
328 328
 			}
329
-			if name == "call16" && strings.Contains(path, asmGo) {
329
+			if (name == "call16" || name == "call32") && strings.Contains(path, asmGo) {
330 330
 				continue
331 331
 			}
332 332
 			c.logf("%s:%d\n  in %s", nicePath(file), line, name)
... ...
@@ -455,7 +464,7 @@ func (tracker *resultTracker) _loopRoutine() {
455 455
 				tracker._waiting += 1
456 456
 			case c = <-tracker._doneChan:
457 457
 				tracker._waiting -= 1
458
-				switch c.status {
458
+				switch c.status() {
459 459
 				case succeededSt:
460 460
 					if c.kind == testKd {
461 461
 						if c.mustFail {
... ...
@@ -601,15 +610,15 @@ func (runner *suiteRunner) run() *Result {
601 601
 		runner.tracker.start()
602 602
 		if runner.checkFixtureArgs() {
603 603
 			c := runner.runFixture(runner.setUpSuite, "", nil)
604
-			if c == nil || c.status == succeededSt {
604
+			if c == nil || c.status() == succeededSt {
605 605
 				for i := 0; i != len(runner.tests); i++ {
606 606
 					c := runner.runTest(runner.tests[i])
607
-					if c.status == fixturePanickedSt {
607
+					if c.status() == fixturePanickedSt {
608 608
 						runner.skipTests(missedSt, runner.tests[i+1:])
609 609
 						break
610 610
 					}
611 611
 				}
612
-			} else if c != nil && c.status == skippedSt {
612
+			} else if c != nil && c.status() == skippedSt {
613 613
 				runner.skipTests(skippedSt, runner.tests)
614 614
 			} else {
615 615
 				runner.skipTests(missedSt, runner.tests)
... ...
@@ -674,22 +683,22 @@ func (runner *suiteRunner) callDone(c *C) {
674 674
 		switch v := value.(type) {
675 675
 		case *fixturePanic:
676 676
 			if v.status == skippedSt {
677
-				c.status = skippedSt
677
+				c.setStatus(skippedSt)
678 678
 			} else {
679 679
 				c.logSoftPanic("Fixture has panicked (see related PANIC)")
680
-				c.status = fixturePanickedSt
680
+				c.setStatus(fixturePanickedSt)
681 681
 			}
682 682
 		default:
683 683
 			c.logPanic(1, value)
684
-			c.status = panickedSt
684
+			c.setStatus(panickedSt)
685 685
 		}
686 686
 	}
687 687
 	if c.mustFail {
688
-		switch c.status {
688
+		switch c.status() {
689 689
 		case failedSt:
690
-			c.status = succeededSt
690
+			c.setStatus(succeededSt)
691 691
 		case succeededSt:
692
-			c.status = failedSt
692
+			c.setStatus(failedSt)
693 693
 			c.logString("Error: Test succeeded, but was expected to fail")
694 694
 			c.logString("Reason: " + c.reason)
695 695
 		}
... ...
@@ -724,11 +733,11 @@ func (runner *suiteRunner) runFixtureWithPanic(method *methodType, testName stri
724 724
 		return nil
725 725
 	}
726 726
 	c := runner.runFixture(method, testName, logb)
727
-	if c != nil && c.status != succeededSt {
727
+	if c != nil && c.status() != succeededSt {
728 728
 		if skipped != nil {
729
-			*skipped = c.status == skippedSt
729
+			*skipped = c.status() == skippedSt
730 730
 		}
731
-		panic(&fixturePanic{c.status, method})
731
+		panic(&fixturePanic{c.status(), method})
732 732
 	}
733 733
 	return c
734 734
 }
... ...
@@ -753,7 +762,7 @@ func (runner *suiteRunner) forkTest(method *methodType) *C {
753 753
 			if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
754 754
 				// Rather than a plain panic, provide a more helpful message when
755 755
 				// the argument type is incorrect.
756
-				c.status = panickedSt
756
+				c.setStatus(panickedSt)
757 757
 				c.logArgPanic(c.method, "*check.C")
758 758
 				return
759 759
 			}
... ...
@@ -773,7 +782,7 @@ func (runner *suiteRunner) forkTest(method *methodType) *C {
773 773
 			c.StartTimer()
774 774
 			c.method.Call([]reflect.Value{reflect.ValueOf(c)})
775 775
 			c.StopTimer()
776
-			if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
776
+			if c.status() != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
777 777
 				return
778 778
 			}
779 779
 			perOpN := int(1e9)
... ...
@@ -808,7 +817,7 @@ func (runner *suiteRunner) runTest(method *methodType) *C {
808 808
 func (runner *suiteRunner) skipTests(status funcStatus, methods []*methodType) {
809 809
 	for _, method := range methods {
810 810
 		runner.runFunc(method, testKd, "", nil, func(c *C) {
811
-			c.status = status
811
+			c.setStatus(status)
812 812
 		})
813 813
 	}
814 814
 }
... ...
@@ -825,7 +834,7 @@ func (runner *suiteRunner) checkFixtureArgs() bool {
825 825
 				succeeded = false
826 826
 				runner.runFunc(method, fixtureKd, "", nil, func(c *C) {
827 827
 					c.logArgPanic(method, "*check.C")
828
-					c.status = panickedSt
828
+					c.setStatus(panickedSt)
829 829
 				})
830 830
 			}
831 831
 		}
... ...
@@ -839,7 +848,7 @@ func (runner *suiteRunner) reportCallStarted(c *C) {
839 839
 
840 840
 func (runner *suiteRunner) reportCallDone(c *C) {
841 841
 	runner.tracker.callDone(c)
842
-	switch c.status {
842
+	switch c.status() {
843 843
 	case succeededSt:
844 844
 		if c.mustFail {
845 845
 			runner.output.WriteCallSuccess("FAIL EXPECTED", c)
... ...
@@ -917,7 +926,7 @@ func (ow *outputWriter) WriteCallSuccess(label string, c *C) {
917 917
 		if c.reason != "" {
918 918
 			suffix = " (" + c.reason + ")"
919 919
 		}
920
-		if c.status == succeededSt {
920
+		if c.status() == succeededSt {
921 921
 			suffix += "\t" + c.timerString()
922 922
 		}
923 923
 		suffix += "\n"
... ...
@@ -16,7 +16,7 @@ func (c *C) TestName() string {
16 16
 
17 17
 // Failed returns whether the currently running test has already failed.
18 18
 func (c *C) Failed() bool {
19
-	return c.status == failedSt
19
+	return c.status() == failedSt
20 20
 }
21 21
 
22 22
 // Fail marks the currently running test as failed.
... ...
@@ -25,7 +25,7 @@ func (c *C) Failed() bool {
25 25
 // what went wrong. The higher level helper functions will fail the test
26 26
 // and do the logging properly.
27 27
 func (c *C) Fail() {
28
-	c.status = failedSt
28
+	c.setStatus(failedSt)
29 29
 }
30 30
 
31 31
 // FailNow marks the currently running test as failed and stops running it.
... ...
@@ -40,7 +40,7 @@ func (c *C) FailNow() {
40 40
 // Succeed marks the currently running test as succeeded, undoing any
41 41
 // previous failures.
42 42
 func (c *C) Succeed() {
43
-	c.status = succeededSt
43
+	c.setStatus(succeededSt)
44 44
 }
45 45
 
46 46
 // SucceedNow marks the currently running test as succeeded, undoing any
... ...
@@ -72,7 +72,7 @@ func (c *C) Skip(reason string) {
72 72
 		panic("Missing reason why the test is being skipped")
73 73
 	}
74 74
 	c.reason = reason
75
-	c.status = skippedSt
75
+	c.setStatus(skippedSt)
76 76
 	c.stopNow()
77 77
 }
78 78
 
79 79
new file mode 100644
... ...
@@ -0,0 +1,4 @@
0
+Godeps/_workspace/bin
1
+Godeps/_workspace/pkg
2
+
3
+*.test
0 4
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+FROM golang:1.5
1
+
2
+RUN go get golang.org/x/tools/cmd/cover
3
+RUN go get github.com/golang/lint/golint
4
+RUN go get golang.org/x/tools/cmd/vet
5
+
6
+WORKDIR /go/src/github.com/vdemeester/shakers
7
+
8
+# enable GO15VENDOREXPERIMENT
9
+ENV GO15VENDOREXPERIMENT 1
10
+
11
+COPY . /go/src/github.com/vdemeester/shakers
0 12
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+.PHONY: all
1
+
2
+SHAKERS_MOUNT := $(if $(BIND_DIR),-v "$(CURDIR)/$(BIND_DIR):/go/src/github.com/vdemeester/shakers/$(BIND_DIR)")
3
+
4
+GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null)
5
+SHAKERS_DEV_IMAGE := shakers-dev$(if $(GIT_BRANCH),:$(GIT_BRANCH))
6
+
7
+DOCKER_RUN_SHAKERS := docker run $(if $(CIRCLECI),,--rm) -it $(SHAKERS_ENVS) $(SHAKERS_MOUNT) "$(SHAKERS_DEV_IMAGE)"
8
+
9
+print-%: ; @echo $*=$($*)
10
+
11
+default: binary
12
+
13
+binary: build
14
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh binary
15
+
16
+test-unit: build
17
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh test-unit
18
+
19
+validate: build
20
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-gofmt validate-golint validate-govet
21
+
22
+validate-govet: build
23
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-govet
24
+
25
+validate-golint: build
26
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-golint
27
+
28
+validate-gofmt: build
29
+	$(DOCKER_RUN_SHAKERS) ./script/make.sh validate-gofmt
30
+
31
+build:
32
+	docker build -t "$(SHAKERS_DEV_IMAGE)" .
33
+
34
+shell: build
35
+	$(DOCKER_RUN_SHAKERS) /bin/bash
36
+
37
+run-dev:
38
+	go build
39
+	./traefik
0 40
new file mode 100644
... ...
@@ -0,0 +1,24 @@
0
+# Shakers
1
+🐹 + 🐙 = 😽 [![Circle CI](https://circleci.com/gh/vdemeester/shakers.svg?style=svg)](https://circleci.com/gh/vdemeester/shakers)
2
+
3
+A collection of `go-check` Checkers to ease the use of it.
4
+
5
+## Building and testing it
6
+
7
+You need either [docker](https://github.com/docker/docker), or `go`
8
+and `godep` in order to build and test shakers.
9
+
10
+### Using Docker and Makefile
11
+
12
+You need to run the ``test-unit`` target. 
13
+```bash
14
+$ make test-unit
15
+docker build -t "shakers-dev:master" .
16
+# […]
17
+docker run --rm -it   "shakers-dev:master" ./script/make.sh test-unit
18
+---> Making bundle: test-unit (in .)
19
++ go test -cover -coverprofile=cover.out .
20
+ok      github.com/vdemeester/shakers   0.015s  coverage: 96.0% of statements
21
+
22
+Test success
23
+```
0 24
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+package shakers
1
+
2
+import (
3
+	"github.com/go-check/check"
4
+)
5
+
6
+// True checker verifies the obtained value is true
7
+//
8
+//    c.Assert(myBool, True)
9
+//
10
+var True check.Checker = &boolChecker{
11
+	&check.CheckerInfo{
12
+		Name:   "True",
13
+		Params: []string{"obtained"},
14
+	},
15
+	true,
16
+}
17
+
18
+// False checker verifies the obtained value is false
19
+//
20
+//    c.Assert(myBool, False)
21
+//
22
+var False check.Checker = &boolChecker{
23
+	&check.CheckerInfo{
24
+		Name:   "False",
25
+		Params: []string{"obtained"},
26
+	},
27
+	false,
28
+}
29
+
30
+type boolChecker struct {
31
+	*check.CheckerInfo
32
+	expected bool
33
+}
34
+
35
+func (checker *boolChecker) Check(params []interface{}, names []string) (bool, string) {
36
+	return is(checker.expected, params[0])
37
+}
38
+
39
+func is(expected bool, obtained interface{}) (bool, string) {
40
+	obtainedBool, ok := obtained.(bool)
41
+	if !ok {
42
+		return false, "obtained value must be a bool."
43
+	}
44
+	return obtainedBool == expected, ""
45
+}
0 46
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+machine:
1
+  services:
2
+    - docker
3
+
4
+dependencies:
5
+  override:
6
+    - make validate
7
+
8
+test:
9
+  override:
10
+    - make test-unit
0 11
new file mode 100644
... ...
@@ -0,0 +1,310 @@
0
+package shakers
1
+
2
+import (
3
+	"reflect"
4
+	"time"
5
+
6
+	"github.com/go-check/check"
7
+)
8
+
9
+// As a commodity, we bring all check.Checker variables into the current namespace to avoid having
10
+// to think about check.X versus checker.X.
11
+var (
12
+	DeepEquals   = check.DeepEquals
13
+	ErrorMatches = check.ErrorMatches
14
+	FitsTypeOf   = check.FitsTypeOf
15
+	HasLen       = check.HasLen
16
+	Implements   = check.Implements
17
+	IsNil        = check.IsNil
18
+	Matches      = check.Matches
19
+	Not          = check.Not
20
+	NotNil       = check.NotNil
21
+	PanicMatches = check.PanicMatches
22
+	Panics       = check.Panics
23
+)
24
+
25
+// Equaler is an interface implemented if the type has a Equal method.
26
+// This is used to compare struct using shakers.Equals.
27
+type Equaler interface {
28
+	Equal(Equaler) bool
29
+}
30
+
31
+// Equals checker verifies the obtained value is equal to the specified one.
32
+// It's is smart in a wait that it supports several *types* (built-in, Equaler,
33
+// time.Time)
34
+//
35
+//    c.Assert(myStruct, Equals, aStruct, check.Commentf("bouuuhh"))
36
+//    c.Assert(myTime, Equals, aTime, check.Commentf("bouuuhh"))
37
+//
38
+var Equals check.Checker = &equalChecker{
39
+	&check.CheckerInfo{
40
+		Name:   "Equals",
41
+		Params: []string{"obtained", "expected"},
42
+	},
43
+}
44
+
45
+type equalChecker struct {
46
+	*check.CheckerInfo
47
+}
48
+
49
+func (checker *equalChecker) Check(params []interface{}, names []string) (bool, string) {
50
+	return isEqual(params[0], params[1])
51
+}
52
+
53
+func isEqual(obtained, expected interface{}) (bool, string) {
54
+	switch obtained.(type) {
55
+	case time.Time:
56
+		return timeEquals(obtained, expected)
57
+	case Equaler:
58
+		return equalerEquals(obtained, expected)
59
+	default:
60
+		if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
61
+			return false, "obtained value and expected value have not the same type."
62
+		}
63
+		return obtained == expected, ""
64
+	}
65
+}
66
+
67
+func equalerEquals(obtained, expected interface{}) (bool, string) {
68
+	expectedEqualer, ok := expected.(Equaler)
69
+	if !ok {
70
+		return false, "expected value must be an Equaler - implementing Equal(Equaler)."
71
+	}
72
+	obtainedEqualer, ok := obtained.(Equaler)
73
+	if !ok {
74
+		return false, "obtained value must be an Equaler - implementing Equal(Equaler)."
75
+	}
76
+	return obtainedEqualer.Equal(expectedEqualer), ""
77
+}
78
+
79
+// GreaterThan checker verifies the obtained value is greater than the specified one.
80
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
81
+//
82
+//    c.Assert(myTime, GreaterThan, aTime, check.Commentf("bouuuhh"))
83
+//    c.Assert(myInt, GreaterThan, 2, check.Commentf("bouuuhh"))
84
+//
85
+var GreaterThan check.Checker = &greaterThanChecker{
86
+	&check.CheckerInfo{
87
+		Name:   "GreaterThan",
88
+		Params: []string{"obtained", "expected"},
89
+	},
90
+}
91
+
92
+type greaterThanChecker struct {
93
+	*check.CheckerInfo
94
+}
95
+
96
+func (checker *greaterThanChecker) Check(params []interface{}, names []string) (bool, string) {
97
+	return greaterThan(params[0], params[1])
98
+}
99
+
100
+func greaterThan(obtained, expected interface{}) (bool, string) {
101
+	if _, ok := obtained.(time.Time); ok {
102
+		return isAfter(obtained, expected)
103
+	}
104
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
105
+		return false, "obtained value and expected value have not the same type."
106
+	}
107
+	switch v := obtained.(type) {
108
+	case float32:
109
+		return v > expected.(float32), ""
110
+	case float64:
111
+		return v > expected.(float64), ""
112
+	case int:
113
+		return v > expected.(int), ""
114
+	case int8:
115
+		return v > expected.(int8), ""
116
+	case int16:
117
+		return v > expected.(int16), ""
118
+	case int32:
119
+		return v > expected.(int32), ""
120
+	case int64:
121
+		return v > expected.(int64), ""
122
+	case uint:
123
+		return v > expected.(uint), ""
124
+	case uint8:
125
+		return v > expected.(uint8), ""
126
+	case uint16:
127
+		return v > expected.(uint16), ""
128
+	case uint32:
129
+		return v > expected.(uint32), ""
130
+	case uint64:
131
+		return v > expected.(uint64), ""
132
+	default:
133
+		return false, "obtained value type not supported."
134
+	}
135
+}
136
+
137
+// GreaterOrEqualThan checker verifies the obtained value is greater or equal than the specified one.
138
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
139
+//
140
+//    c.Assert(myTime, GreaterOrEqualThan, aTime, check.Commentf("bouuuhh"))
141
+//    c.Assert(myInt, GreaterOrEqualThan, 2, check.Commentf("bouuuhh"))
142
+//
143
+var GreaterOrEqualThan check.Checker = &greaterOrEqualThanChecker{
144
+	&check.CheckerInfo{
145
+		Name:   "GreaterOrEqualThan",
146
+		Params: []string{"obtained", "expected"},
147
+	},
148
+}
149
+
150
+type greaterOrEqualThanChecker struct {
151
+	*check.CheckerInfo
152
+}
153
+
154
+func (checker *greaterOrEqualThanChecker) Check(params []interface{}, names []string) (bool, string) {
155
+	return greaterOrEqualThan(params[0], params[1])
156
+}
157
+
158
+func greaterOrEqualThan(obtained, expected interface{}) (bool, string) {
159
+	if _, ok := obtained.(time.Time); ok {
160
+		return isAfter(obtained, expected)
161
+	}
162
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
163
+		return false, "obtained value and expected value have not the same type."
164
+	}
165
+	switch v := obtained.(type) {
166
+	case float32:
167
+		return v >= expected.(float32), ""
168
+	case float64:
169
+		return v >= expected.(float64), ""
170
+	case int:
171
+		return v >= expected.(int), ""
172
+	case int8:
173
+		return v >= expected.(int8), ""
174
+	case int16:
175
+		return v >= expected.(int16), ""
176
+	case int32:
177
+		return v >= expected.(int32), ""
178
+	case int64:
179
+		return v >= expected.(int64), ""
180
+	case uint:
181
+		return v >= expected.(uint), ""
182
+	case uint8:
183
+		return v >= expected.(uint8), ""
184
+	case uint16:
185
+		return v >= expected.(uint16), ""
186
+	case uint32:
187
+		return v >= expected.(uint32), ""
188
+	case uint64:
189
+		return v >= expected.(uint64), ""
190
+	default:
191
+		return false, "obtained value type not supported."
192
+	}
193
+}
194
+
195
+// LessThan checker verifies the obtained value is less than the specified one.
196
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
197
+//
198
+//    c.Assert(myTime, LessThan, aTime, check.Commentf("bouuuhh"))
199
+//    c.Assert(myInt, LessThan, 2, check.Commentf("bouuuhh"))
200
+//
201
+var LessThan check.Checker = &lessThanChecker{
202
+	&check.CheckerInfo{
203
+		Name:   "LessThan",
204
+		Params: []string{"obtained", "expected"},
205
+	},
206
+}
207
+
208
+type lessThanChecker struct {
209
+	*check.CheckerInfo
210
+}
211
+
212
+func (checker *lessThanChecker) Check(params []interface{}, names []string) (bool, string) {
213
+	return lessThan(params[0], params[1])
214
+}
215
+
216
+func lessThan(obtained, expected interface{}) (bool, string) {
217
+	if _, ok := obtained.(time.Time); ok {
218
+		return isBefore(obtained, expected)
219
+	}
220
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
221
+		return false, "obtained value and expected value have not the same type."
222
+	}
223
+	switch v := obtained.(type) {
224
+	case float32:
225
+		return v < expected.(float32), ""
226
+	case float64:
227
+		return v < expected.(float64), ""
228
+	case int:
229
+		return v < expected.(int), ""
230
+	case int8:
231
+		return v < expected.(int8), ""
232
+	case int16:
233
+		return v < expected.(int16), ""
234
+	case int32:
235
+		return v < expected.(int32), ""
236
+	case int64:
237
+		return v < expected.(int64), ""
238
+	case uint:
239
+		return v < expected.(uint), ""
240
+	case uint8:
241
+		return v < expected.(uint8), ""
242
+	case uint16:
243
+		return v < expected.(uint16), ""
244
+	case uint32:
245
+		return v < expected.(uint32), ""
246
+	case uint64:
247
+		return v < expected.(uint64), ""
248
+	default:
249
+		return false, "obtained value type not supported."
250
+	}
251
+}
252
+
253
+// LessOrEqualThan checker verifies the obtained value is less or equal than the specified one.
254
+// It's is smart in a wait that it supports several *types* (built-in, time.Time)
255
+//
256
+//    c.Assert(myTime, LessThan, aTime, check.Commentf("bouuuhh"))
257
+//    c.Assert(myInt, LessThan, 2, check.Commentf("bouuuhh"))
258
+//
259
+var LessOrEqualThan check.Checker = &lessOrEqualThanChecker{
260
+	&check.CheckerInfo{
261
+		Name:   "LessOrEqualThan",
262
+		Params: []string{"obtained", "expected"},
263
+	},
264
+}
265
+
266
+type lessOrEqualThanChecker struct {
267
+	*check.CheckerInfo
268
+}
269
+
270
+func (checker *lessOrEqualThanChecker) Check(params []interface{}, names []string) (bool, string) {
271
+	return lessOrEqualThan(params[0], params[1])
272
+}
273
+
274
+func lessOrEqualThan(obtained, expected interface{}) (bool, string) {
275
+	if _, ok := obtained.(time.Time); ok {
276
+		return isBefore(obtained, expected)
277
+	}
278
+	if reflect.TypeOf(obtained) != reflect.TypeOf(expected) {
279
+		return false, "obtained value and expected value have not the same type."
280
+	}
281
+	switch v := obtained.(type) {
282
+	case float32:
283
+		return v <= expected.(float32), ""
284
+	case float64:
285
+		return v <= expected.(float64), ""
286
+	case int:
287
+		return v <= expected.(int), ""
288
+	case int8:
289
+		return v <= expected.(int8), ""
290
+	case int16:
291
+		return v <= expected.(int16), ""
292
+	case int32:
293
+		return v <= expected.(int32), ""
294
+	case int64:
295
+		return v <= expected.(int64), ""
296
+	case uint:
297
+		return v <= expected.(uint), ""
298
+	case uint8:
299
+		return v <= expected.(uint8), ""
300
+	case uint16:
301
+		return v <= expected.(uint16), ""
302
+	case uint32:
303
+		return v <= expected.(uint32), ""
304
+	case uint64:
305
+		return v <= expected.(uint64), ""
306
+	default:
307
+		return false, "obtained value type not supported."
308
+	}
309
+}
0 310
new file mode 100644
... ...
@@ -0,0 +1,4 @@
0
+package: main
1
+import:
2
+  - package: github.com/go-check/check
3
+    ref:     11d3bc7aa68e238947792f30573146a3231fc0f1
0 4
new file mode 100644
... ...
@@ -0,0 +1,168 @@
0
+// Package shakers provide some checker implementation the go-check.Checker interface.
1
+package shakers
2
+
3
+import (
4
+	"fmt"
5
+	"strings"
6
+
7
+	"github.com/go-check/check"
8
+)
9
+
10
+// Contains checker verifies that obtained value contains a substring.
11
+var Contains check.Checker = &substringChecker{
12
+	&check.CheckerInfo{
13
+		Name:   "Contains",
14
+		Params: []string{"obtained", "substring"},
15
+	},
16
+	strings.Contains,
17
+}
18
+
19
+// ContainsAny checker verifies that any Unicode code points in chars
20
+// are in the obtained string.
21
+var ContainsAny check.Checker = &substringChecker{
22
+	&check.CheckerInfo{
23
+		Name:   "ContainsAny",
24
+		Params: []string{"obtained", "chars"},
25
+	},
26
+	strings.ContainsAny,
27
+}
28
+
29
+// HasPrefix checker verifies that obtained value has the specified substring as prefix
30
+var HasPrefix check.Checker = &substringChecker{
31
+	&check.CheckerInfo{
32
+		Name:   "HasPrefix",
33
+		Params: []string{"obtained", "prefix"},
34
+	},
35
+	strings.HasPrefix,
36
+}
37
+
38
+// HasSuffix checker verifies that obtained value has the specified substring as prefix
39
+var HasSuffix check.Checker = &substringChecker{
40
+	&check.CheckerInfo{
41
+		Name:   "HasSuffix",
42
+		Params: []string{"obtained", "suffix"},
43
+	},
44
+	strings.HasSuffix,
45
+}
46
+
47
+// EqualFold checker verifies that obtained value is, interpreted as UTF-8 strings, are equal under Unicode case-folding.
48
+var EqualFold check.Checker = &substringChecker{
49
+	&check.CheckerInfo{
50
+		Name:   "EqualFold",
51
+		Params: []string{"obtained", "expected"},
52
+	},
53
+	strings.EqualFold,
54
+}
55
+
56
+type substringChecker struct {
57
+	*check.CheckerInfo
58
+	substringFunction func(string, string) bool
59
+}
60
+
61
+func (checker *substringChecker) Check(params []interface{}, names []string) (bool, string) {
62
+	obtained := params[0]
63
+	substring := params[1]
64
+	substringStr, ok := substring.(string)
65
+	if !ok {
66
+		return false, fmt.Sprintf("%s value must be a string.", names[1])
67
+	}
68
+	obtainedString, obtainedIsStr := obtained.(string)
69
+	if !obtainedIsStr {
70
+		if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer {
71
+			obtainedString, obtainedIsStr = obtainedWithStringer.String(), true
72
+		}
73
+	}
74
+	if obtainedIsStr {
75
+		return checker.substringFunction(obtainedString, substringStr), ""
76
+	}
77
+	return false, "obtained value is not a string and has no .String()."
78
+}
79
+
80
+// 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
81
+var IndexAny check.Checker = &substringCountChecker{
82
+	&check.CheckerInfo{
83
+		Name:   "IndexAny",
84
+		Params: []string{"obtained", "chars", "expected"},
85
+	},
86
+	strings.IndexAny,
87
+}
88
+
89
+// Index checker verifies that the index of the first instance of sep in the obtained value is equal to expected
90
+var Index check.Checker = &substringCountChecker{
91
+	&check.CheckerInfo{
92
+		Name:   "Index",
93
+		Params: []string{"obtained", "sep", "expected"},
94
+	},
95
+	strings.Index,
96
+}
97
+
98
+// Count checker verifies that obtained value has the specified number of non-overlapping instances of sep
99
+var Count check.Checker = &substringCountChecker{
100
+	&check.CheckerInfo{
101
+		Name:   "Count",
102
+		Params: []string{"obtained", "sep", "expected"},
103
+	},
104
+	strings.Count,
105
+}
106
+
107
+type substringCountChecker struct {
108
+	*check.CheckerInfo
109
+	substringFunction func(string, string) int
110
+}
111
+
112
+func (checker *substringCountChecker) Check(params []interface{}, names []string) (bool, string) {
113
+	obtained := params[0]
114
+	substring := params[1]
115
+	expected := params[2]
116
+	substringStr, ok := substring.(string)
117
+	if !ok {
118
+		return false, fmt.Sprintf("%s value must be a string.", names[1])
119
+	}
120
+	obtainedString, obtainedIsStr := obtained.(string)
121
+	if !obtainedIsStr {
122
+		if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer {
123
+			obtainedString, obtainedIsStr = obtainedWithStringer.String(), true
124
+		}
125
+	}
126
+	if obtainedIsStr {
127
+		return checker.substringFunction(obtainedString, substringStr) == expected, ""
128
+	}
129
+	return false, "obtained value is not a string and has no .String()."
130
+}
131
+
132
+// IsLower checker verifies that the obtained value is in lower case
133
+var IsLower check.Checker = &stringTransformChecker{
134
+	&check.CheckerInfo{
135
+		Name:   "IsLower",
136
+		Params: []string{"obtained"},
137
+	},
138
+	strings.ToLower,
139
+}
140
+
141
+// IsUpper checker verifies that the obtained value is in lower case
142
+var IsUpper check.Checker = &stringTransformChecker{
143
+	&check.CheckerInfo{
144
+		Name:   "IsUpper",
145
+		Params: []string{"obtained"},
146
+	},
147
+	strings.ToUpper,
148
+}
149
+
150
+type stringTransformChecker struct {
151
+	*check.CheckerInfo
152
+	stringFunction func(string) string
153
+}
154
+
155
+func (checker *stringTransformChecker) Check(params []interface{}, names []string) (bool, string) {
156
+	obtained := params[0]
157
+	obtainedString, obtainedIsStr := obtained.(string)
158
+	if !obtainedIsStr {
159
+		if obtainedWithStringer, obtainedHasStringer := obtained.(fmt.Stringer); obtainedHasStringer {
160
+			obtainedString, obtainedIsStr = obtainedWithStringer.String(), true
161
+		}
162
+	}
163
+	if obtainedIsStr {
164
+		return checker.stringFunction(obtainedString) == obtainedString, ""
165
+	}
166
+	return false, "obtained value is not a string and has no .String()."
167
+}
0 168
new file mode 100644
... ...
@@ -0,0 +1,234 @@
0
+package shakers
1
+
2
+import (
3
+	"fmt"
4
+	"time"
5
+
6
+	"github.com/go-check/check"
7
+)
8
+
9
+// Default format when parsing (in addition to RFC and default time formats..)
10
+const shortForm = "2006-01-02"
11
+
12
+// IsBefore checker verifies the specified value is before the specified time.
13
+// It is exclusive.
14
+//
15
+//    c.Assert(myTime, IsBefore, theTime, check.Commentf("bouuuhhh"))
16
+//
17
+var IsBefore check.Checker = &isBeforeChecker{
18
+	&check.CheckerInfo{
19
+		Name:   "IsBefore",
20
+		Params: []string{"obtained", "expected"},
21
+	},
22
+}
23
+
24
+type isBeforeChecker struct {
25
+	*check.CheckerInfo
26
+}
27
+
28
+func (checker *isBeforeChecker) Check(params []interface{}, names []string) (bool, string) {
29
+	return isBefore(params[0], params[1])
30
+}
31
+
32
+func isBefore(value, t interface{}) (bool, string) {
33
+	tTime, ok := parseTime(t)
34
+	if !ok {
35
+		return false, "expected must be a Time struct, or parseable."
36
+	}
37
+	valueTime, valueIsTime := parseTime(value)
38
+	if valueIsTime {
39
+		return valueTime.Before(tTime), ""
40
+	}
41
+	return false, "obtained value is not a time.Time struct or parseable as a time."
42
+}
43
+
44
+// IsAfter checker verifies the specified value is before the specified time.
45
+// It is exclusive.
46
+//
47
+//    c.Assert(myTime, IsAfter, theTime, check.Commentf("bouuuhhh"))
48
+//
49
+var IsAfter check.Checker = &isAfterChecker{
50
+	&check.CheckerInfo{
51
+		Name:   "IsAfter",
52
+		Params: []string{"obtained", "expected"},
53
+	},
54
+}
55
+
56
+type isAfterChecker struct {
57
+	*check.CheckerInfo
58
+}
59
+
60
+func (checker *isAfterChecker) Check(params []interface{}, names []string) (bool, string) {
61
+	return isAfter(params[0], params[1])
62
+}
63
+
64
+func isAfter(value, t interface{}) (bool, string) {
65
+	tTime, ok := parseTime(t)
66
+	if !ok {
67
+		return false, "expected must be a Time struct, or parseable."
68
+	}
69
+	valueTime, valueIsTime := parseTime(value)
70
+	if valueIsTime {
71
+		return valueTime.After(tTime), ""
72
+	}
73
+	return false, "obtained value is not a time.Time struct or parseable as a time."
74
+}
75
+
76
+// IsBetween checker verifies the specified time is between the specified start
77
+// and end. It's exclusive so if the specified time is at the tip of the interval.
78
+//
79
+//    c.Assert(myTime, IsBetween, startTime, endTime, check.Commentf("bouuuhhh"))
80
+//
81
+var IsBetween check.Checker = &isBetweenChecker{
82
+	&check.CheckerInfo{
83
+		Name:   "IsBetween",
84
+		Params: []string{"obtained", "start", "end"},
85
+	},
86
+}
87
+
88
+type isBetweenChecker struct {
89
+	*check.CheckerInfo
90
+}
91
+
92
+func (checker *isBetweenChecker) Check(params []interface{}, names []string) (bool, string) {
93
+	return isBetween(params[0], params[1], params[2])
94
+}
95
+
96
+func isBetween(value, start, end interface{}) (bool, string) {
97
+	startTime, ok := parseTime(start)
98
+	if !ok {
99
+		return false, "start must be a Time struct, or parseable."
100
+	}
101
+	endTime, ok := parseTime(end)
102
+	if !ok {
103
+		return false, "end must be a Time struct, or parseable."
104
+	}
105
+	valueTime, valueIsTime := parseTime(value)
106
+	if valueIsTime {
107
+		return valueTime.After(startTime) && valueTime.Before(endTime), ""
108
+	}
109
+	return false, "obtained value is not a time.Time struct or parseable as a time."
110
+}
111
+
112
+// TimeEquals checker verifies the specified time is the equal to the expected
113
+// time.
114
+//
115
+//    c.Assert(myTime, TimeEquals, expected, check.Commentf("bouhhh"))
116
+//
117
+// It's possible to ignore some part of the time (like hours, minutes, etc..) using
118
+// the TimeIgnore checker with it.
119
+//
120
+//    c.Assert(myTime, TimeIgnore(TimeEquals, time.Hour), expected, check.Commentf("... bouh.."))
121
+//
122
+var TimeEquals check.Checker = &timeEqualsChecker{
123
+	&check.CheckerInfo{
124
+		Name:   "TimeEquals",
125
+		Params: []string{"obtained", "expected"},
126
+	},
127
+}
128
+
129
+type timeEqualsChecker struct {
130
+	*check.CheckerInfo
131
+}
132
+
133
+func (checker *timeEqualsChecker) Check(params []interface{}, names []string) (bool, string) {
134
+	return timeEquals(params[0], params[1])
135
+}
136
+
137
+func timeEquals(obtained, expected interface{}) (bool, string) {
138
+	expectedTime, ok := parseTime(expected)
139
+	if !ok {
140
+		return false, "expected must be a Time struct, or parseable."
141
+	}
142
+	valueTime, valueIsTime := parseTime(obtained)
143
+	if valueIsTime {
144
+		return valueTime.Equal(expectedTime), ""
145
+	}
146
+	return false, "obtained value is not a time.Time struct or parseable as a time."
147
+}
148
+
149
+// TimeIgnore checker will ignore some part of the time on the encapsulated checker.
150
+//
151
+//    c.Assert(myTime, TimeIgnore(IsBetween, time.Second), start, end)
152
+//
153
+// FIXME use interface{} for ignore (to enable "Month", ..
154
+func TimeIgnore(checker check.Checker, ignore time.Duration) check.Checker {
155
+	return &timeIgnoreChecker{
156
+		sub:    checker,
157
+		ignore: ignore,
158
+	}
159
+}
160
+
161
+type timeIgnoreChecker struct {
162
+	sub    check.Checker
163
+	ignore time.Duration
164
+}
165
+
166
+func (checker *timeIgnoreChecker) Info() *check.CheckerInfo {
167
+	info := *checker.sub.Info()
168
+	info.Name = fmt.Sprintf("TimeIgnore(%s, %v)", info.Name, checker.ignore)
169
+	return &info
170
+}
171
+
172
+func (checker *timeIgnoreChecker) Check(params []interface{}, names []string) (bool, string) {
173
+	// Naive implementation : all params are supposed to be date
174
+	mParams := make([]interface{}, len(params))
175
+	for index, param := range params {
176
+		paramTime, ok := parseTime(param)
177
+		if !ok {
178
+			return false, fmt.Sprintf("%s must be a Time struct, or parseable.", names[index])
179
+		}
180
+		year := paramTime.Year()
181
+		month := paramTime.Month()
182
+		day := paramTime.Day()
183
+		hour := paramTime.Hour()
184
+		min := paramTime.Minute()
185
+		sec := paramTime.Second()
186
+		nsec := paramTime.Nanosecond()
187
+		location := paramTime.Location()
188
+		switch checker.ignore {
189
+		case time.Hour:
190
+			hour = 0
191
+			fallthrough
192
+		case time.Minute:
193
+			min = 0
194
+			fallthrough
195
+		case time.Second:
196
+			sec = 0
197
+			fallthrough
198
+		case time.Millisecond:
199
+			fallthrough
200
+		case time.Microsecond:
201
+			fallthrough
202
+		case time.Nanosecond:
203
+			nsec = 0
204
+		}
205
+		mParams[index] = time.Date(year, month, day, hour, min, sec, nsec, location)
206
+	}
207
+	return checker.sub.Check(mParams, names)
208
+}
209
+
210
+func parseTime(datetime interface{}) (time.Time, bool) {
211
+	switch datetime.(type) {
212
+	case time.Time:
213
+		return datetime.(time.Time), true
214
+	case string:
215
+		return parseTimeAsString(datetime.(string))
216
+	default:
217
+		if datetimeWithStr, ok := datetime.(fmt.Stringer); ok {
218
+			return parseTimeAsString(datetimeWithStr.String())
219
+		}
220
+		return time.Time{}, false
221
+	}
222
+}
223
+
224
+func parseTimeAsString(timeAsStr string) (time.Time, bool) {
225
+	forms := []string{shortForm, time.RFC3339, time.RFC3339Nano, time.RFC822, time.RFC822Z}
226
+	for _, form := range forms {
227
+		datetime, err := time.Parse(form, timeAsStr)
228
+		if err == nil {
229
+			return datetime, true
230
+		}
231
+	}
232
+	return time.Time{}, false
233
+}