1
0
Fork 0
mirror of https://github.com/Luzifer/cloudkeys-go.git synced 2024-11-14 17:02:43 +00:00
cloudkeys-go/vendor/github.com/juju/testing/checkers/checker.go

256 lines
6.5 KiB
Go
Raw Normal View History

2017-12-28 01:56:23 +00:00
// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the LGPLv3, see LICENCE file for details.
package checkers
import (
"fmt"
"reflect"
"strings"
"time"
gc "gopkg.in/check.v1"
)
func TimeBetween(start, end time.Time) gc.Checker {
if end.Before(start) {
return &timeBetweenChecker{end, start}
}
return &timeBetweenChecker{start, end}
}
type timeBetweenChecker struct {
start, end time.Time
}
func (checker *timeBetweenChecker) Info() *gc.CheckerInfo {
info := gc.CheckerInfo{
Name: "TimeBetween",
Params: []string{"obtained"},
}
return &info
}
func (checker *timeBetweenChecker) Check(params []interface{}, names []string) (result bool, error string) {
when, ok := params[0].(time.Time)
if !ok {
return false, "obtained value type must be time.Time"
}
if when.Before(checker.start) {
return false, fmt.Sprintf("obtained time %q is before start time %q", when, checker.start)
}
if when.After(checker.end) {
return false, fmt.Sprintf("obtained time %q is after end time %q", when, checker.end)
}
return true, ""
}
// DurationLessThan checker
type durationLessThanChecker struct {
*gc.CheckerInfo
}
var DurationLessThan gc.Checker = &durationLessThanChecker{
&gc.CheckerInfo{Name: "DurationLessThan", Params: []string{"obtained", "expected"}},
}
func (checker *durationLessThanChecker) Check(params []interface{}, names []string) (result bool, error string) {
obtained, ok := params[0].(time.Duration)
if !ok {
return false, "obtained value type must be time.Duration"
}
expected, ok := params[1].(time.Duration)
if !ok {
return false, "expected value type must be time.Duration"
}
return obtained.Nanoseconds() < expected.Nanoseconds(), ""
}
// HasPrefix checker for checking strings
func stringOrStringer(value interface{}) (string, bool) {
result, isString := value.(string)
if !isString {
if stringer, isStringer := value.(fmt.Stringer); isStringer {
result, isString = stringer.String(), true
}
}
return result, isString
}
type hasPrefixChecker struct {
*gc.CheckerInfo
}
var HasPrefix gc.Checker = &hasPrefixChecker{
&gc.CheckerInfo{Name: "HasPrefix", Params: []string{"obtained", "expected"}},
}
func (checker *hasPrefixChecker) Check(params []interface{}, names []string) (result bool, error string) {
expected, ok := params[1].(string)
if !ok {
return false, "expected must be a string"
}
obtained, isString := stringOrStringer(params[0])
if isString {
return strings.HasPrefix(obtained, expected), ""
}
return false, "Obtained value is not a string and has no .String()"
}
type hasSuffixChecker struct {
*gc.CheckerInfo
}
var HasSuffix gc.Checker = &hasSuffixChecker{
&gc.CheckerInfo{Name: "HasSuffix", Params: []string{"obtained", "expected"}},
}
func (checker *hasSuffixChecker) Check(params []interface{}, names []string) (result bool, error string) {
expected, ok := params[1].(string)
if !ok {
return false, "expected must be a string"
}
obtained, isString := stringOrStringer(params[0])
if isString {
return strings.HasSuffix(obtained, expected), ""
}
return false, "Obtained value is not a string and has no .String()"
}
type containsChecker struct {
*gc.CheckerInfo
}
var Contains gc.Checker = &containsChecker{
&gc.CheckerInfo{Name: "Contains", Params: []string{"obtained", "expected"}},
}
func (checker *containsChecker) Check(params []interface{}, names []string) (result bool, error string) {
expected, ok := params[1].(string)
if !ok {
return false, "expected must be a string"
}
obtained, isString := stringOrStringer(params[0])
if isString {
return strings.Contains(obtained, expected), ""
}
return false, "Obtained value is not a string and has no .String()"
}
type sameContents struct {
*gc.CheckerInfo
}
// SameContents checks that the obtained slice contains all the values (and
// same number of values) of the expected slice and vice versa, without respect
// to order or duplicates. Uses DeepEquals on mapped contents to compare.
var SameContents gc.Checker = &sameContents{
&gc.CheckerInfo{Name: "SameContents", Params: []string{"obtained", "expected"}},
}
func (checker *sameContents) Check(params []interface{}, names []string) (result bool, error string) {
if len(params) != 2 {
return false, "SameContents expects two slice arguments"
}
obtained := params[0]
expected := params[1]
tob := reflect.TypeOf(obtained)
if tob.Kind() != reflect.Slice {
return false, fmt.Sprintf("SameContents expects the obtained value to be a slice, got %q",
tob.Kind())
}
texp := reflect.TypeOf(expected)
if texp.Kind() != reflect.Slice {
return false, fmt.Sprintf("SameContents expects the expected value to be a slice, got %q",
texp.Kind())
}
if texp != tob {
return false, fmt.Sprintf(
"SameContents expects two slices of the same type, expected: %q, got: %q",
texp, tob)
}
vexp := reflect.ValueOf(expected)
vob := reflect.ValueOf(obtained)
length := vexp.Len()
if vob.Len() != length {
// Slice has incorrect number of elements
return false, ""
}
// spin up maps with the entries as keys and the counts as values
mob := make(map[interface{}]int, length)
mexp := make(map[interface{}]int, length)
for i := 0; i < length; i++ {
mexp[reflect.Indirect(vexp.Index(i)).Interface()]++
mob[reflect.Indirect(vob.Index(i)).Interface()]++
}
return reflect.DeepEqual(mob, mexp), ""
}
type errorIsNilChecker struct {
*gc.CheckerInfo
}
// The ErrorIsNil checker tests whether the obtained value is nil.
// Explicitly tests against only `nil`.
//
// For example:
//
// c.Assert(err, ErrorIsNil)
//
var ErrorIsNil gc.Checker = &errorIsNilChecker{
&gc.CheckerInfo{Name: "ErrorIsNil", Params: []string{"value"}},
}
type ErrorStacker interface {
error
StackTrace() []string
}
func (checker *errorIsNilChecker) Check(params []interface{}, names []string) (bool, string) {
result, message := errorIsNil(params[0])
if !result {
if stacker, ok := params[0].(ErrorStacker); ok && message == "" {
stack := stacker.StackTrace()
if stack != nil {
message = "error stack:\n\t" + strings.Join(stack, "\n\t")
}
}
}
return result, message
}
func errorIsNil(obtained interface{}) (result bool, message string) {
if obtained == nil {
return true, ""
}
if _, ok := obtained.(error); !ok {
return false, fmt.Sprintf("obtained type (%T) is not an error", obtained)
}
switch v := reflect.ValueOf(obtained); v.Kind() {
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
if v.IsNil() {
return false, fmt.Sprintf("value of (%T) is nil, but a typed nil", obtained)
}
}
return false, ""
}