Retry temporary errors by default (#107)

* Adding Aurora URL validator in order to handle scenarios where incomplete information is passed to the client. The client will do its best to guess the missing information such as protocol and port.

* Upgraded to testify 1.3.0.

* Added configuration to fail on a non-temporary error. This is reverting to the original behavior of the retry mechanism. However, this allows the user to opt to fail in a non-temporary error.
This commit is contained in:
Renan DelValle 2019-06-11 11:47:14 -07:00 committed by GitHub
parent 4ffb509939
commit 6dc4bf93b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 2795 additions and 1009 deletions

6
Gopkg.lock generated
View file

@ -40,15 +40,15 @@
revision = "471cd4e61d7a78ece1791fa5faa0345dc8c7d5a5" revision = "471cd4e61d7a78ece1791fa5faa0345dc8c7d5a5"
[[projects]] [[projects]]
digest = "1:2d0dc026c4aef5e2f3a0e06a4dabe268b840d8f63190cf6894e02134a03f52c5" digest = "1:381bcbeb112a51493d9d998bbba207a529c73dbb49b3fd789e48c63fac1f192c"
name = "github.com/stretchr/testify" name = "github.com/stretchr/testify"
packages = [ packages = [
"assert", "assert",
"require", "require",
] ]
pruneopts = "" pruneopts = ""
revision = "b91bfb9ebec76498946beb6af7c0230c7cc7ba6c" revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053"
version = "v1.2.0" version = "v1.3.0"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"

View file

@ -12,5 +12,5 @@
[[constraint]] [[constraint]]
name = "github.com/stretchr/testify" name = "github.com/stretchr/testify"
version = "1.2.0" version = "1.3.0"

12
job.go
View file

@ -178,7 +178,9 @@ func (j *AuroraJob) GPU(gpu int64) Job {
// rejects jobs with GPU resources attached to it. // rejects jobs with GPU resources attached to it.
if _, ok := j.resources[GPU]; !ok { if _, ok := j.resources[GPU]; !ok {
j.resources[GPU] = &aurora.Resource{} j.resources[GPU] = &aurora.Resource{}
j.JobConfig().GetTaskConfig().Resources = append(j.JobConfig().GetTaskConfig().Resources, j.resources[GPU]) j.JobConfig().GetTaskConfig().Resources = append(
j.JobConfig().GetTaskConfig().Resources,
j.resources[GPU])
} }
j.resources[GPU].NumGpus = &gpu j.resources[GPU].NumGpus = &gpu
@ -259,7 +261,9 @@ func (j *AuroraJob) AddLabel(key string, value string) Job {
func (j *AuroraJob) AddNamedPorts(names ...string) Job { func (j *AuroraJob) AddNamedPorts(names ...string) Job {
j.portCount += len(names) j.portCount += len(names)
for _, name := range names { for _, name := range names {
j.jobConfig.TaskConfig.Resources = append(j.jobConfig.TaskConfig.Resources, &aurora.Resource{NamedPort: &name}) j.jobConfig.TaskConfig.Resources = append(
j.jobConfig.TaskConfig.Resources,
&aurora.Resource{NamedPort: &name})
} }
return j return j
@ -274,7 +278,9 @@ func (j *AuroraJob) AddPorts(num int) Job {
j.portCount += num j.portCount += num
for i := start; i < j.portCount; i++ { for i := start; i < j.portCount; i++ {
portName := "org.apache.aurora.port." + strconv.Itoa(i) portName := "org.apache.aurora.port." + strconv.Itoa(i)
j.jobConfig.TaskConfig.Resources = append(j.jobConfig.TaskConfig.Resources, &aurora.Resource{NamedPort: &portName}) j.jobConfig.TaskConfig.Resources = append(
j.jobConfig.TaskConfig.Resources,
&aurora.Resource{NamedPort: &portName})
} }
return j return j

View file

@ -27,7 +27,10 @@ type Monitor struct {
} }
// Polls the scheduler every certain amount of time to see if the update has succeeded // Polls the scheduler every certain amount of time to see if the update has succeeded
func (m *Monitor) JobUpdate(updateKey aurora.JobUpdateKey, interval int, timeout int) (bool, error) { func (m *Monitor) JobUpdate(
updateKey aurora.JobUpdateKey,
interval int,
timeout int) (bool, error) {
updateQ := aurora.JobUpdateQuery{ updateQ := aurora.JobUpdateQuery{
Key: &updateKey, Key: &updateKey,
@ -40,7 +43,10 @@ func (m *Monitor) JobUpdate(updateKey aurora.JobUpdateKey, interval int, timeout
aurora.JobUpdateStatus_FAILED, aurora.JobUpdateStatus_FAILED,
}, },
} }
updateSummaries, err := m.JobUpdateQuery(updateQ, time.Duration(interval)*time.Second, time.Duration(timeout)*time.Second) updateSummaries, err := m.JobUpdateQuery(
updateQ,
time.Duration(interval)*time.Second,
time.Duration(timeout)*time.Second)
status := updateSummaries[0].State.Status status := updateSummaries[0].State.Status
@ -119,7 +125,10 @@ func (m *Monitor) JobUpdateQuery(
} }
// Monitor a Job until all instances enter one of the LIVE_STATES // Monitor a Job until all instances enter one of the LIVE_STATES
func (m *Monitor) Instances(key *aurora.JobKey, instances int32, interval, timeout int) (bool, error) { func (m *Monitor) Instances(
key *aurora.JobKey,
instances int32,
interval, timeout int) (bool, error) {
return m.ScheduleStatus(key, instances, LiveStates, interval, timeout) return m.ScheduleStatus(key, instances, LiveStates, interval, timeout)
} }
@ -164,9 +173,13 @@ func (m *Monitor) ScheduleStatus(
} }
} }
// Monitor host status until all hosts match the status provided. Returns a map where the value is true if the host // Monitor host status until all hosts match the status provided.
// Returns a map where the value is true if the host
// is in one of the desired mode(s) or false if it is not as of the time when the monitor exited. // is in one of the desired mode(s) or false if it is not as of the time when the monitor exited.
func (m *Monitor) HostMaintenance(hosts []string, modes []aurora.MaintenanceMode, interval, timeout int) (map[string]bool, error) { func (m *Monitor) HostMaintenance(
hosts []string,
modes []aurora.MaintenanceMode,
interval, timeout int) (map[string]bool, error) {
// Transform modes to monitor for into a set for easy lookup // Transform modes to monitor for into a set for easy lookup
desiredMode := make(map[aurora.MaintenanceMode]struct{}) desiredMode := make(map[aurora.MaintenanceMode]struct{})
@ -175,7 +188,8 @@ func (m *Monitor) HostMaintenance(hosts []string, modes []aurora.MaintenanceMode
} }
// Turn slice into a host set to eliminate duplicates. // Turn slice into a host set to eliminate duplicates.
// We also can't use a simple count because multiple modes means we can have multiple matches for a single host. // We also can't use a simple count because multiple modes means
// we can have multiple matches for a single host.
// I.e. host A transitions from ACTIVE to DRAINING to DRAINED while monitored // I.e. host A transitions from ACTIVE to DRAINING to DRAINED while monitored
remainingHosts := make(map[string]struct{}) remainingHosts := make(map[string]struct{})
for _, host := range hosts { for _, host := range hosts {

129
realis.go
View file

@ -16,6 +16,7 @@
package realis package realis
import ( import (
"context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
@ -31,19 +32,23 @@ import (
"time" "time"
"github.com/apache/thrift/lib/go/thrift" "github.com/apache/thrift/lib/go/thrift"
"github.com/pkg/errors"
"github.com/paypal/gorealis/gen-go/apache/aurora" "github.com/paypal/gorealis/gen-go/apache/aurora"
"github.com/paypal/gorealis/response" "github.com/paypal/gorealis/response"
"github.com/pkg/errors"
) )
const VERSION = "1.21.0" const VERSION = "1.21.1"
// TODO(rdelvalle): Move documentation to interface in order to make godoc look better/more accessible // TODO(rdelvalle): Move documentation to interface in order to make godoc look better accessible
// Or get rid of the interface
type Realis interface { type Realis interface {
AbortJobUpdate(updateKey aurora.JobUpdateKey, message string) (*aurora.Response, error) AbortJobUpdate(updateKey aurora.JobUpdateKey, message string) (*aurora.Response, error)
AddInstances(instKey aurora.InstanceKey, count int32) (*aurora.Response, error) AddInstances(instKey aurora.InstanceKey, count int32) (*aurora.Response, error)
CreateJob(auroraJob Job) (*aurora.Response, error) CreateJob(auroraJob Job) (*aurora.Response, error)
CreateService(auroraJob Job, settings *aurora.JobUpdateSettings) (*aurora.Response, *aurora.StartJobUpdateResult_, error) CreateService(
auroraJob Job,
settings *aurora.JobUpdateSettings) (*aurora.Response, *aurora.StartJobUpdateResult_, error)
DescheduleCronJob(key *aurora.JobKey) (*aurora.Response, error) DescheduleCronJob(key *aurora.JobKey) (*aurora.Response, error)
FetchTaskConfig(instKey aurora.InstanceKey) (*aurora.TaskConfig, error) FetchTaskConfig(instKey aurora.InstanceKey) (*aurora.TaskConfig, error)
GetInstanceIds(key *aurora.JobKey, states []aurora.ScheduleStatus) ([]int32, error) GetInstanceIds(key *aurora.JobKey, states []aurora.ScheduleStatus) ([]int32, error)
@ -108,13 +113,14 @@ type RealisConfig struct {
transport thrift.TTransport transport thrift.TTransport
protoFactory thrift.TProtocolFactory protoFactory thrift.TProtocolFactory
logger *LevelLogger logger *LevelLogger
InsecureSkipVerify bool insecureSkipVerify bool
certspath string certspath string
clientKey, clientCert string clientKey, clientCert string
options []ClientOption options []ClientOption
debug bool debug bool
trace bool trace bool
zkOptions []ZKOpt zkOptions []ZKOpt
failOnPermanentErrors bool
} }
var defaultBackoff = Backoff{ var defaultBackoff = Backoff{
@ -124,11 +130,10 @@ var defaultBackoff = Backoff{
Jitter: 0.1, Jitter: 0.1,
} }
const APIPath = "/api" // ClientOption - An alias for a function that modifies the realis config object
type ClientOption func(*RealisConfig) type ClientOption func(*RealisConfig)
//Config sets for options in RealisConfig. // BasicAuth - Set authentication used against Apache Shiro in the Aurora scheduler
func BasicAuth(username, password string) ClientOption { func BasicAuth(username, password string) ClientOption {
return func(config *RealisConfig) { return func(config *RealisConfig) {
config.username = username config.username = username
@ -136,26 +141,29 @@ func BasicAuth(username, password string) ClientOption {
} }
} }
// SchedulerUrl - Set the immediate location of the current Aurora scheduler leader
func SchedulerUrl(url string) ClientOption { func SchedulerUrl(url string) ClientOption {
return func(config *RealisConfig) { return func(config *RealisConfig) {
config.url = url config.url = url
} }
} }
// TimeoutMS - Set the connection timeout for an HTTP post request in Miliseconds
func TimeoutMS(timeout int) ClientOption { func TimeoutMS(timeout int) ClientOption {
return func(config *RealisConfig) { return func(config *RealisConfig) {
config.timeoutms = timeout config.timeoutms = timeout
} }
} }
// ZKCluster - Set a clusters.json provided cluster configuration to the client
func ZKCluster(cluster *Cluster) ClientOption { func ZKCluster(cluster *Cluster) ClientOption {
return func(config *RealisConfig) { return func(config *RealisConfig) {
config.cluster = cluster config.cluster = cluster
} }
} }
// ZKUrl - Set the direct location of a Zookeeper node on which the Aurora leader registers itself
func ZKUrl(url string) ClientOption { func ZKUrl(url string) ClientOption {
opts := []ZKOpt{ZKEndpoints(strings.Split(url, ",")...), ZKPath("/aurora/scheduler")} opts := []ZKOpt{ZKEndpoints(strings.Split(url, ",")...), ZKPath("/aurora/scheduler")}
return func(config *RealisConfig) { return func(config *RealisConfig) {
@ -167,6 +175,7 @@ func ZKUrl(url string) ClientOption {
} }
} }
// Retries - Configure the retry mechanism for the client
func Retries(backoff Backoff) ClientOption { func Retries(backoff Backoff) ClientOption {
return func(config *RealisConfig) { return func(config *RealisConfig) {
config.backoff = backoff config.backoff = backoff
@ -191,9 +200,9 @@ func BackOff(b Backoff) ClientOption {
} }
} }
func InsecureSkipVerify(InsecureSkipVerify bool) ClientOption { func InsecureSkipVerify(insecureSkipVerify bool) ClientOption {
return func(config *RealisConfig) { return func(config *RealisConfig) {
config.InsecureSkipVerify = InsecureSkipVerify config.insecureSkipVerify = insecureSkipVerify
} }
} }
@ -238,12 +247,24 @@ func Trace() ClientOption {
} }
} }
// FailOnPermanentErrors - If the client encounters a connection error the standard library
// considers permanent, stop retrying and return an error to the user.
func FailOnPermanentErrors() ClientOption {
return func(config *RealisConfig) {
config.failOnPermanentErrors = true
}
}
func newTJSONTransport(url string, timeout int, config *RealisConfig) (thrift.TTransport, error) { func newTJSONTransport(url string, timeout int, config *RealisConfig) (thrift.TTransport, error) {
trans, err := defaultTTransport(url, timeout, config) trans, err := defaultTTransport(url, timeout, config)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to create transport") return nil, errors.Wrap(err, "unable to create transport")
} }
httpTrans := (trans).(*thrift.THttpClient) httpTrans, ok := (trans).(*thrift.THttpClient)
if !ok {
return nil, errors.Wrap(err, "transport does not contain a thrift client")
}
httpTrans.SetHeader("Content-Type", "application/x-thrift") httpTrans.SetHeader("Content-Type", "application/x-thrift")
httpTrans.SetHeader("User-Agent", "gorealis v"+VERSION) httpTrans.SetHeader("User-Agent", "gorealis v"+VERSION)
return trans, err return trans, err
@ -254,7 +275,11 @@ func newTBinTransport(url string, timeout int, config *RealisConfig) (thrift.TTr
if err != nil { if err != nil {
return nil, errors.Wrap(err, "unable to create transport") return nil, errors.Wrap(err, "unable to create transport")
} }
httpTrans := (trans).(*thrift.THttpClient) httpTrans, ok := (trans).(*thrift.THttpClient)
if !ok {
return nil, errors.Wrap(err, "transport does not contain a thrift client")
}
httpTrans.DelHeader("Content-Type") // Workaround for using thrift HttpPostClient httpTrans.DelHeader("Content-Type") // Workaround for using thrift HttpPostClient
httpTrans.SetHeader("Accept", "application/vnd.apache.thrift.binary") httpTrans.SetHeader("Accept", "application/vnd.apache.thrift.binary")
httpTrans.SetHeader("Content-Type", "application/vnd.apache.thrift.binary") httpTrans.SetHeader("Content-Type", "application/vnd.apache.thrift.binary")
@ -328,7 +353,7 @@ func NewRealisClient(options ...ClientOption) (Realis, error) {
url, err = LeaderFromZK(*config.cluster) url, err = LeaderFromZK(*config.cluster)
// If ZK is configured, throw an error if the leader is unable to be determined // If ZK is configured, throw an error if the leader is unable to be determined
if err != nil { if err != nil {
return nil, NewTemporaryError(errors.Wrap(err, "unable to use zk to get leader ")) return nil, NewTemporaryError(errors.Wrap(err, "unable to use zk to get leader"))
} }
config.logger.Println("Scheduler URL from ZK: ", url) config.logger.Println("Scheduler URL from ZK: ", url)
} else if config.url != "" { } else if config.url != "" {
@ -338,6 +363,13 @@ func NewRealisClient(options ...ClientOption) (Realis, error) {
return nil, errors.New("incomplete Options -- url, cluster.json, or Zookeeper address required") return nil, errors.New("incomplete Options -- url, cluster.json, or Zookeeper address required")
} }
config.logger.Println("Addresss obtained: ", url)
url, err = validateAuroraURL(url)
if err != nil {
return nil, errors.Wrap(err, "invalid Aurora url")
}
config.logger.Println("Corrected address: ", url)
if config.jsonTransport { if config.jsonTransport {
trans, err := newTJSONTransport(url, config.timeoutms, config) trans, err := newTJSONTransport(url, config.timeoutms, config)
if err != nil { if err != nil {
@ -359,7 +391,10 @@ func NewRealisClient(options ...ClientOption) (Realis, error) {
// Adding Basic Authentication. // Adding Basic Authentication.
if config.username != "" && config.password != "" { if config.username != "" && config.password != "" {
httpTrans := (config.transport).(*thrift.THttpClient) httpTrans, ok := (config.transport).(*thrift.THttpClient)
if !ok {
return nil, errors.New("transport provided does not contain an THttpClient")
}
httpTrans.SetHeader("Authorization", "Basic "+basicAuth(config.username, config.password)) httpTrans.SetHeader("Authorization", "Basic "+basicAuth(config.username, config.password))
} }
@ -405,7 +440,7 @@ func GetCerts(certPath string) (*x509.CertPool, error) {
func defaultTTransport(url string, timeoutMs int, config *RealisConfig) (thrift.TTransport, error) { func defaultTTransport(url string, timeoutMs int, config *RealisConfig) (thrift.TTransport, error) {
var transport http.Transport var transport http.Transport
if config != nil { if config != nil {
tlsConfig := &tls.Config{InsecureSkipVerify: config.InsecureSkipVerify} tlsConfig := &tls.Config{InsecureSkipVerify: config.insecureSkipVerify}
if config.certspath != "" { if config.certspath != "" {
rootCAs, err := GetCerts(config.certspath) rootCAs, err := GetCerts(config.certspath)
@ -433,11 +468,13 @@ func defaultTTransport(url string, timeoutMs int, config *RealisConfig) (thrift.
} }
trans, err := thrift.NewTHttpClientWithOptions( trans, err := thrift.NewTHttpClientWithOptions(
url+APIPath, url,
thrift.THttpClientOptions{ thrift.THttpClientOptions{
Client: &http.Client{ Client: &http.Client{
Timeout: time.Millisecond * time.Duration(timeoutMs), Timeout: time.Millisecond * time.Duration(timeoutMs),
Transport: &transport}}) Transport: &transport,
},
})
if err != nil { if err != nil {
return nil, errors.Wrap(err, "Error creating transport") return nil, errors.Wrap(err, "Error creating transport")
@ -504,7 +541,7 @@ func (r *realisClient) GetInstanceIds(key *aurora.JobKey, states []aurora.Schedu
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.GetTasksWithoutConfigs(nil, taskQ) return r.client.GetTasksWithoutConfigs(context.TODO(), taskQ)
}) })
// If we encountered an error we couldn't recover from by retrying, return an error to the user // If we encountered an error we couldn't recover from by retrying, return an error to the user
@ -529,7 +566,7 @@ func (r *realisClient) GetJobUpdateSummaries(jobUpdateQuery *aurora.JobUpdateQue
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.readonlyClient.GetJobUpdateSummaries(nil, jobUpdateQuery) return r.readonlyClient.GetJobUpdateSummaries(context.TODO(), jobUpdateQuery)
}) })
if retryErr != nil { if retryErr != nil {
@ -546,7 +583,7 @@ func (r *realisClient) GetJobs(role string) (*aurora.Response, *aurora.GetJobsRe
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.readonlyClient.GetJobs(nil, role) return r.readonlyClient.GetJobs(context.TODO(), role)
}) })
if retryErr != nil { if retryErr != nil {
@ -567,7 +604,7 @@ func (r *realisClient) KillInstances(key *aurora.JobKey, instances ...int32) (*a
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.KillTasks(nil, key, instances, "") return r.client.KillTasks(context.TODO(), key, instances, "")
}) })
if retryErr != nil { if retryErr != nil {
@ -589,7 +626,7 @@ func (r *realisClient) KillJob(key *aurora.JobKey) (*aurora.Response, error) {
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
// Giving the KillTasks thrift call an empty set tells the Aurora scheduler to kill all active shards // Giving the KillTasks thrift call an empty set tells the Aurora scheduler to kill all active shards
return r.client.KillTasks(nil, key, nil, "") return r.client.KillTasks(context.TODO(), key, nil, "")
}) })
if retryErr != nil { if retryErr != nil {
@ -609,7 +646,7 @@ func (r *realisClient) CreateJob(auroraJob Job) (*aurora.Response, error) {
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.CreateJob(nil, auroraJob.JobConfig()) return r.client.CreateJob(context.TODO(), auroraJob.JobConfig())
}) })
if retryErr != nil { if retryErr != nil {
@ -619,7 +656,9 @@ func (r *realisClient) CreateJob(auroraJob Job) (*aurora.Response, error) {
} }
// This API uses an update thrift call to create the services giving a few more robust features. // This API uses an update thrift call to create the services giving a few more robust features.
func (r *realisClient) CreateService(auroraJob Job, settings *aurora.JobUpdateSettings) (*aurora.Response, *aurora.StartJobUpdateResult_, error) { func (r *realisClient) CreateService(
auroraJob Job,
settings *aurora.JobUpdateSettings) (*aurora.Response, *aurora.StartJobUpdateResult_, error) {
// Create a new job update object and ship it to the StartJobUpdate api // Create a new job update object and ship it to the StartJobUpdate api
update := NewUpdateJob(auroraJob.TaskConfig(), settings) update := NewUpdateJob(auroraJob.TaskConfig(), settings)
update.InstanceCount(auroraJob.GetInstanceCount()) update.InstanceCount(auroraJob.GetInstanceCount())
@ -646,7 +685,7 @@ func (r *realisClient) ScheduleCronJob(auroraJob Job) (*aurora.Response, error)
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.ScheduleCronJob(nil, auroraJob.JobConfig()) return r.client.ScheduleCronJob(context.TODO(), auroraJob.JobConfig())
}) })
if retryErr != nil { if retryErr != nil {
@ -662,7 +701,7 @@ func (r *realisClient) DescheduleCronJob(key *aurora.JobKey) (*aurora.Response,
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.DescheduleCronJob(nil, key) return r.client.DescheduleCronJob(context.TODO(), key)
}) })
if retryErr != nil { if retryErr != nil {
@ -680,7 +719,7 @@ func (r *realisClient) StartCronJob(key *aurora.JobKey) (*aurora.Response, error
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.StartCronJob(nil, key) return r.client.StartCronJob(context.TODO(), key)
}) })
if retryErr != nil { if retryErr != nil {
@ -697,7 +736,7 @@ func (r *realisClient) RestartInstances(key *aurora.JobKey, instances ...int32)
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.RestartShards(nil, key, instances) return r.client.RestartShards(context.TODO(), key, instances)
}) })
if retryErr != nil { if retryErr != nil {
@ -720,7 +759,7 @@ func (r *realisClient) RestartJob(key *aurora.JobKey) (*aurora.Response, error)
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.RestartShards(nil, key, instanceIds) return r.client.RestartShards(context.TODO(), key, instanceIds)
}) })
if retryErr != nil { if retryErr != nil {
@ -741,7 +780,7 @@ func (r *realisClient) StartJobUpdate(updateJob *UpdateJob, message string) (*au
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
true, true,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.StartJobUpdate(nil, updateJob.req, message) return r.client.StartJobUpdate(context.TODO(), updateJob.req, message)
}) })
if retryErr != nil { if retryErr != nil {
@ -765,7 +804,7 @@ func (r *realisClient) AbortJobUpdate(updateKey aurora.JobUpdateKey, message str
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.AbortJobUpdate(nil, &updateKey, message) return r.client.AbortJobUpdate(context.TODO(), &updateKey, message)
}) })
if retryErr != nil { if retryErr != nil {
@ -774,7 +813,11 @@ func (r *realisClient) AbortJobUpdate(updateKey aurora.JobUpdateKey, message str
// Make this call synchronous by blocking until it job has successfully transitioned to aborted // Make this call synchronous by blocking until it job has successfully transitioned to aborted
m := Monitor{Client: r} m := Monitor{Client: r}
_, err := m.JobUpdateStatus(updateKey, map[aurora.JobUpdateStatus]bool{aurora.JobUpdateStatus_ABORTED: true}, time.Second*5, time.Minute) _, err := m.JobUpdateStatus(
updateKey,
map[aurora.JobUpdateStatus]bool{aurora.JobUpdateStatus_ABORTED: true},
time.Second*5,
time.Minute)
return resp, err return resp, err
} }
@ -787,7 +830,7 @@ func (r *realisClient) PauseJobUpdate(updateKey *aurora.JobUpdateKey, message st
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.PauseJobUpdate(nil, updateKey, message) return r.client.PauseJobUpdate(context.TODO(), updateKey, message)
}) })
if retryErr != nil { if retryErr != nil {
@ -805,7 +848,7 @@ func (r *realisClient) ResumeJobUpdate(updateKey *aurora.JobUpdateKey, message s
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.ResumeJobUpdate(nil, updateKey, message) return r.client.ResumeJobUpdate(context.TODO(), updateKey, message)
}) })
if retryErr != nil { if retryErr != nil {
@ -823,7 +866,7 @@ func (r *realisClient) PulseJobUpdate(updateKey *aurora.JobUpdateKey) (*aurora.R
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.PulseJobUpdate(nil, updateKey) return r.client.PulseJobUpdate(context.TODO(), updateKey)
}) })
if retryErr != nil { if retryErr != nil {
@ -842,7 +885,7 @@ func (r *realisClient) AddInstances(instKey aurora.InstanceKey, count int32) (*a
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.AddInstances(nil, &instKey, count) return r.client.AddInstances(context.TODO(), &instKey, count)
}) })
if retryErr != nil { if retryErr != nil {
@ -881,7 +924,7 @@ func (r *realisClient) GetTaskStatus(query *aurora.TaskQuery) ([]*aurora.Schedul
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.GetTasksStatus(nil, query) return r.client.GetTasksStatus(context.TODO(), query)
}) })
if retryErr != nil { if retryErr != nil {
@ -899,7 +942,7 @@ func (r *realisClient) GetPendingReason(query *aurora.TaskQuery) ([]*aurora.Pend
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.GetPendingReason(nil, query) return r.client.GetPendingReason(context.TODO(), query)
}) })
if retryErr != nil { if retryErr != nil {
@ -923,7 +966,7 @@ func (r *realisClient) GetTasksWithoutConfigs(query *aurora.TaskQuery) ([]*auror
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.GetTasksWithoutConfigs(nil, query) return r.client.GetTasksWithoutConfigs(context.TODO(), query)
}) })
if retryErr != nil { if retryErr != nil {
@ -949,7 +992,7 @@ func (r *realisClient) FetchTaskConfig(instKey aurora.InstanceKey) (*aurora.Task
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.GetTasksStatus(nil, taskQ) return r.client.GetTasksStatus(context.TODO(), taskQ)
}) })
if retryErr != nil { if retryErr != nil {
@ -977,7 +1020,7 @@ func (r *realisClient) JobUpdateDetails(updateQuery aurora.JobUpdateQuery) (*aur
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.GetJobUpdateDetails(nil, &updateQuery) return r.client.GetJobUpdateDetails(context.TODO(), &updateQuery)
}) })
if retryErr != nil { if retryErr != nil {
@ -994,7 +1037,7 @@ func (r *realisClient) RollbackJobUpdate(key aurora.JobUpdateKey, message string
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.client.RollbackJobUpdate(nil, &key, message) return r.client.RollbackJobUpdate(context.TODO(), &key, message)
}) })
if retryErr != nil { if retryErr != nil {

View file

@ -1,6 +1,8 @@
package realis package realis
import ( import (
"context"
"github.com/paypal/gorealis/gen-go/apache/aurora" "github.com/paypal/gorealis/gen-go/apache/aurora"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -27,7 +29,7 @@ func (r *realisClient) DrainHosts(hosts ...string) (*aurora.Response, *aurora.Dr
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.DrainHosts(nil, drainList) return r.adminClient.DrainHosts(context.TODO(), drainList)
}) })
if retryErr != nil { if retryErr != nil {
@ -44,7 +46,10 @@ func (r *realisClient) DrainHosts(hosts ...string) (*aurora.Response, *aurora.Dr
// Start SLA Aware Drain. // Start SLA Aware Drain.
// defaultSlaPolicy is the fallback SlaPolicy to use if a task does not have an SlaPolicy. // defaultSlaPolicy is the fallback SlaPolicy to use if a task does not have an SlaPolicy.
// After timeoutSecs, tasks will be forcefully drained without checking SLA. // After timeoutSecs, tasks will be forcefully drained without checking SLA.
func (r *realisClient) SLADrainHosts(policy *aurora.SlaPolicy, timeout int64, hosts ...string) (*aurora.DrainHostsResult_, error) { func (r *realisClient) SLADrainHosts(
policy *aurora.SlaPolicy,
timeout int64,
hosts ...string) (*aurora.DrainHostsResult_, error) {
var result *aurora.DrainHostsResult_ var result *aurora.DrainHostsResult_
if len(hosts) == 0 { if len(hosts) == 0 {
@ -59,7 +64,7 @@ func (r *realisClient) SLADrainHosts(policy *aurora.SlaPolicy, timeout int64, ho
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.SlaDrainHosts(nil, drainList, policy, timeout) return r.adminClient.SlaDrainHosts(context.TODO(), drainList, policy, timeout)
}) })
if retryErr != nil { if retryErr != nil {
@ -89,7 +94,7 @@ func (r *realisClient) StartMaintenance(hosts ...string) (*aurora.Response, *aur
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.StartMaintenance(nil, hostList) return r.adminClient.StartMaintenance(context.TODO(), hostList)
}) })
if retryErr != nil { if retryErr != nil {
@ -119,7 +124,7 @@ func (r *realisClient) EndMaintenance(hosts ...string) (*aurora.Response, *auror
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.EndMaintenance(nil, hostList) return r.adminClient.EndMaintenance(context.TODO(), hostList)
}) })
if retryErr != nil { if retryErr != nil {
@ -151,7 +156,7 @@ func (r *realisClient) MaintenanceStatus(hosts ...string) (*aurora.Response, *au
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.MaintenanceStatus(nil, hostList) return r.adminClient.MaintenanceStatus(context.TODO(), hostList)
}) })
if retryErr != nil { if retryErr != nil {
@ -166,7 +171,8 @@ func (r *realisClient) MaintenanceStatus(hosts ...string) (*aurora.Response, *au
} }
// SetQuota sets a quota aggregate for the given role // SetQuota sets a quota aggregate for the given role
// TODO(zircote) Currently investigating an error that is returned from thrift calls that include resources for `NamedPort` and `NumGpu` // TODO(zircote) Currently investigating an error that is returned
// from thrift calls that include resources for `NamedPort` and `NumGpu`
func (r *realisClient) SetQuota(role string, cpu *float64, ramMb *int64, diskMb *int64) (*aurora.Response, error) { func (r *realisClient) SetQuota(role string, cpu *float64, ramMb *int64, diskMb *int64) (*aurora.Response, error) {
quota := &aurora.ResourceAggregate{ quota := &aurora.ResourceAggregate{
Resources: []*aurora.Resource{{NumCpus: cpu}, {RamMb: ramMb}, {DiskMb: diskMb}}, Resources: []*aurora.Resource{{NumCpus: cpu}, {RamMb: ramMb}, {DiskMb: diskMb}},
@ -175,7 +181,7 @@ func (r *realisClient) SetQuota(role string, cpu *float64, ramMb *int64, diskMb
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.SetQuota(nil, role, quota) return r.adminClient.SetQuota(context.TODO(), role, quota)
}) })
if retryErr != nil { if retryErr != nil {
@ -191,7 +197,7 @@ func (r *realisClient) GetQuota(role string) (*aurora.Response, error) {
resp, retryErr := r.thriftCallWithRetries( resp, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.GetQuota(nil, role) return r.adminClient.GetQuota(context.TODO(), role)
}) })
if retryErr != nil { if retryErr != nil {
@ -206,7 +212,7 @@ func (r *realisClient) Snapshot() error {
_, retryErr := r.thriftCallWithRetries( _, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.Snapshot(nil) return r.adminClient.Snapshot(context.TODO())
}) })
if retryErr != nil { if retryErr != nil {
@ -222,7 +228,7 @@ func (r *realisClient) PerformBackup() error {
_, retryErr := r.thriftCallWithRetries( _, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.PerformBackup(nil) return r.adminClient.PerformBackup(context.TODO())
}) })
if retryErr != nil { if retryErr != nil {
@ -237,7 +243,7 @@ func (r *realisClient) ForceImplicitTaskReconciliation() error {
_, retryErr := r.thriftCallWithRetries( _, retryErr := r.thriftCallWithRetries(
false, false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.TriggerImplicitTaskReconciliation(nil) return r.adminClient.TriggerImplicitTaskReconciliation(context.TODO())
}) })
if retryErr != nil { if retryErr != nil {
@ -250,7 +256,7 @@ func (r *realisClient) ForceImplicitTaskReconciliation() error {
func (r *realisClient) ForceExplicitTaskReconciliation(batchSize *int32) error { func (r *realisClient) ForceExplicitTaskReconciliation(batchSize *int32) error {
if batchSize != nil && *batchSize < 1 { if batchSize != nil && *batchSize < 1 {
return errors.New("Invalid batch size.") return errors.New("invalid batch size")
} }
settings := aurora.NewExplicitReconciliationSettings() settings := aurora.NewExplicitReconciliationSettings()
@ -258,7 +264,7 @@ func (r *realisClient) ForceExplicitTaskReconciliation(batchSize *int32) error {
_, retryErr := r.thriftCallWithRetries(false, _, retryErr := r.thriftCallWithRetries(false,
func() (*aurora.Response, error) { func() (*aurora.Response, error) {
return r.adminClient.TriggerExplicitTaskReconciliation(nil, settings) return r.adminClient.TriggerExplicitTaskReconciliation(context.TODO(), settings)
}) })
if retryErr != nil { if retryErr != nil {

View file

@ -65,32 +65,58 @@ func TestMain(m *testing.M) {
} }
func TestNonExistentEndpoint(t *testing.T) { func TestNonExistentEndpoint(t *testing.T) {
backoff := realis.Backoff{ // Reduce penalties for this test to make it quick // Reduce penalties for this test to make it quick
Steps: 5, backoff := realis.Backoff{
Duration: 1 * time.Second, Steps: 3,
Duration: 200 * time.Millisecond,
Factor: 1.0, Factor: 1.0,
Jitter: 0.1} Jitter: 0.1}
// Attempt to connect to a bad endpoint
r, err := realis.NewRealisClient(realis.SchedulerUrl("http://192.168.33.7:8081/doesntexist/"),
realis.TimeoutMS(200),
realis.BackOff(backoff),
)
defer r.Close()
taskQ := &aurora.TaskQuery{} taskQ := &aurora.TaskQuery{}
badEndpoint := "http://idontexist.local:8081/api"
_, err = r.GetTasksWithoutConfigs(taskQ) t.Run("WithRetries", func(t *testing.T) {
// Attempt to connect to a bad endpoint
r, err := realis.NewRealisClient(
realis.SchedulerUrl(badEndpoint),
realis.TimeoutMS(200000),
realis.BackOff(backoff),
)
// Check that we do error out of retrying require.NoError(t, err)
assert.Error(t, err) require.NotNil(t, r)
defer r.Close()
// Check that the error before this one was a a retry error _, err = r.GetTasksWithoutConfigs(taskQ)
// TODO: Consider bubbling up timeout behaving error all the way up to the user.
retryErr := realis.ToRetryCount(errors.Cause(err))
assert.NotNil(t, retryErr, "error passed in is not a retry error")
assert.Equal(t, backoff.Steps, retryErr.RetryCount(), "retry count is incorrect") // Check that we do error out of retrying
require.Error(t, err)
// Check that the error before this one was a a retry error
// TODO: Consider bubbling up timeout behaving error all the way up to the user.
retryErr := realis.ToRetryCount(errors.Cause(err))
require.NotNil(t, retryErr, "error passed in is not a retry error")
assert.Equal(t, backoff.Steps, retryErr.RetryCount(), "retry count is incorrect")
})
t.Run("FailOnLookup", func(t *testing.T) {
// Attempt to connect to a bad endpoint
r, err := realis.NewRealisClient(
realis.SchedulerUrl(badEndpoint),
realis.TimeoutMS(200000),
realis.BackOff(backoff),
realis.FailOnPermanentErrors(),
)
require.NoError(t, err)
require.NotNil(t, r)
defer r.Close()
_, err = r.GetTasksWithoutConfigs(taskQ)
// Check that we do error out of retrying
require.Error(t, err)
})
} }
@ -100,7 +126,8 @@ func TestThriftBinary(t *testing.T) {
realis.TimeoutMS(20000), realis.TimeoutMS(20000),
realis.ThriftBinary()) realis.ThriftBinary())
assert.NoError(t, err) require.NoError(t, err)
defer r.Close()
role := "all" role := "all"
taskQ := &aurora.TaskQuery{ taskQ := &aurora.TaskQuery{
@ -109,11 +136,7 @@ func TestThriftBinary(t *testing.T) {
// Perform a simple API call to test Thrift Binary // Perform a simple API call to test Thrift Binary
_, err = r.GetTasksWithoutConfigs(taskQ) _, err = r.GetTasksWithoutConfigs(taskQ)
assert.NoError(t, err) assert.NoError(t, err)
r.Close()
} }
func TestThriftJSON(t *testing.T) { func TestThriftJSON(t *testing.T) {
@ -122,7 +145,8 @@ func TestThriftJSON(t *testing.T) {
realis.TimeoutMS(20000), realis.TimeoutMS(20000),
realis.ThriftJSON()) realis.ThriftJSON())
assert.NoError(t, err) require.NoError(t, err)
defer r.Close()
role := "all" role := "all"
taskQ := &aurora.TaskQuery{ taskQ := &aurora.TaskQuery{
@ -134,8 +158,6 @@ func TestThriftJSON(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
r.Close()
} }
func TestNoopLogger(t *testing.T) { func TestNoopLogger(t *testing.T) {
@ -143,7 +165,8 @@ func TestNoopLogger(t *testing.T) {
realis.BasicAuth("aurora", "secret"), realis.BasicAuth("aurora", "secret"),
realis.SetLogger(realis.NoopLogger{})) realis.SetLogger(realis.NoopLogger{}))
assert.NoError(t, err) require.NoError(t, err)
defer r.Close()
role := "all" role := "all"
taskQ := &aurora.TaskQuery{ taskQ := &aurora.TaskQuery{
@ -152,24 +175,20 @@ func TestNoopLogger(t *testing.T) {
// Perform a simple API call to test Thrift Binary // Perform a simple API call to test Thrift Binary
_, err = r.GetTasksWithoutConfigs(taskQ) _, err = r.GetTasksWithoutConfigs(taskQ)
assert.NoError(t, err) assert.NoError(t, err)
r.Close()
} }
func TestLeaderFromZK(t *testing.T) { func TestLeaderFromZK(t *testing.T) {
cluster := realis.GetDefaultClusterFromZKUrl("192.168.33.2:2181") cluster := realis.GetDefaultClusterFromZKUrl("192.168.33.2:2181")
url, err := realis.LeaderFromZK(*cluster) url, err := realis.LeaderFromZK(*cluster)
assert.NoError(t, err) require.NoError(t, err)
// Address stored inside of ZK might be different than the one we connect to in our tests. // Address stored inside of ZK might be different than the one we connect to in our tests.
assert.Equal(t, "http://192.168.33.7:8081", url) assert.Equal(t, "http://192.168.33.7:8081", url)
} }
func TestRealisClient_ReestablishConn(t *testing.T) { func TestRealisClient_ReestablishConn(t *testing.T) {
// Test that we're able to tear down the old connection and create a new one. // Test that we're able to tear down the old connection and create a new one.
err := r.ReestablishConn() err := r.ReestablishConn()
@ -178,9 +197,8 @@ func TestRealisClient_ReestablishConn(t *testing.T) {
func TestGetCACerts(t *testing.T) { func TestGetCACerts(t *testing.T) {
certs, err := realis.GetCerts("./examples/certs") certs, err := realis.GetCerts("./examples/certs")
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, len(certs.Subjects()), 2) assert.Equal(t, len(certs.Subjects()), 2)
} }
func TestRealisClient_CreateJob_Thermos(t *testing.T) { func TestRealisClient_CreateJob_Thermos(t *testing.T) {
@ -200,7 +218,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
AddPorts(1) AddPorts(1)
_, err := r.CreateJob(job) _, err := r.CreateJob(job)
assert.NoError(t, err) require.NoError(t, err)
// Test Instances Monitor // Test Instances Monitor
success, err := monitor.Instances(job.JobKey(), job.GetInstanceCount(), 1, 50) success, err := monitor.Instances(job.JobKey(), job.GetInstanceCount(), 1, 50)
@ -228,7 +246,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
status, err := r.GetTaskStatus(&aurora.TaskQuery{ status, err := r.GetTaskStatus(&aurora.TaskQuery{
JobKeys: []*aurora.JobKey{job.JobKey()}, JobKeys: []*aurora.JobKey{job.JobKey()},
Statuses: []aurora.ScheduleStatus{aurora.ScheduleStatus_RUNNING}}) Statuses: []aurora.ScheduleStatus{aurora.ScheduleStatus_RUNNING}})
assert.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, status) assert.NotNil(t, status)
assert.Len(t, status, 2) assert.Len(t, status, 2)
@ -237,7 +255,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
t.Run("AddInstances", func(t *testing.T) { t.Run("AddInstances", func(t *testing.T) {
_, err := r.AddInstances(aurora.InstanceKey{JobKey: job.JobKey(), InstanceId: 0}, 2) _, err := r.AddInstances(aurora.InstanceKey{JobKey: job.JobKey(), InstanceId: 0}, 2)
assert.NoError(t, err) require.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 4, 1, 50) success, err := monitor.Instances(job.JobKey(), 4, 1, 50)
assert.True(t, success) assert.True(t, success)
assert.NoError(t, err) assert.NoError(t, err)
@ -245,7 +263,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
t.Run("KillInstances", func(t *testing.T) { t.Run("KillInstances", func(t *testing.T) {
_, err := r.KillInstances(job.JobKey(), 2, 3) _, err := r.KillInstances(job.JobKey(), 2, 3)
assert.NoError(t, err) require.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 2, 1, 50) success, err := monitor.Instances(job.JobKey(), 2, 1, 50)
assert.True(t, success) assert.True(t, success)
assert.NoError(t, err) assert.NoError(t, err)
@ -253,7 +271,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
t.Run("RestartInstances", func(t *testing.T) { t.Run("RestartInstances", func(t *testing.T) {
_, err := r.RestartInstances(job.JobKey(), 0) _, err := r.RestartInstances(job.JobKey(), 0)
assert.NoError(t, err) require.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 2, 1, 50) success, err := monitor.Instances(job.JobKey(), 2, 1, 50)
assert.True(t, success) assert.True(t, success)
assert.NoError(t, err) assert.NoError(t, err)
@ -261,7 +279,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
t.Run("RestartJobs", func(t *testing.T) { t.Run("RestartJobs", func(t *testing.T) {
_, err := r.RestartJob(job.JobKey()) _, err := r.RestartJob(job.JobKey())
assert.NoError(t, err) require.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 2, 1, 50) success, err := monitor.Instances(job.JobKey(), 2, 1, 50)
assert.True(t, success) assert.True(t, success)
assert.NoError(t, err) assert.NoError(t, err)
@ -270,7 +288,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
// Tasks must exist for it to, be killed // Tasks must exist for it to, be killed
t.Run("KillJob", func(t *testing.T) { t.Run("KillJob", func(t *testing.T) {
_, err := r.KillJob(job.JobKey()) _, err := r.KillJob(job.JobKey())
assert.NoError(t, err) require.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 0, 1, 50) success, err := monitor.Instances(job.JobKey(), 0, 1, 50)
assert.True(t, success) assert.True(t, success)
assert.NoError(t, err) assert.NoError(t, err)
@ -285,7 +303,7 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
AddLabel("chips", "chips") AddLabel("chips", "chips")
_, err := r.CreateJob(job) _, err := r.CreateJob(job)
assert.NoError(t, err) require.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 2, 1, 50) success, err := monitor.Instances(job.JobKey(), 2, 1, 50)
assert.True(t, success) assert.True(t, success)
@ -298,7 +316,6 @@ func TestRealisClient_CreateJob_Thermos(t *testing.T) {
// Test configuring an executor that doesn't exist for CreateJob API // Test configuring an executor that doesn't exist for CreateJob API
func TestRealisClient_CreateJob_ExecutorDoesNotExist(t *testing.T) { func TestRealisClient_CreateJob_ExecutorDoesNotExist(t *testing.T) {
// Create a single job // Create a single job
job := realis.NewJob(). job := realis.NewJob().
Environment("prod"). Environment("prod").
@ -336,7 +353,7 @@ func TestRealisClient_GetPendingReason(t *testing.T) {
InstanceCount(1) InstanceCount(1)
resp, err := r.CreateJob(job) resp, err := r.CreateJob(job)
assert.NoError(t, err) require.NoError(t, err)
assert.Equal(t, aurora.ResponseCode_OK, resp.ResponseCode) assert.Equal(t, aurora.ResponseCode_OK, resp.ResponseCode)
taskQ := &aurora.TaskQuery{ taskQ := &aurora.TaskQuery{
@ -349,7 +366,7 @@ func TestRealisClient_GetPendingReason(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, reasons, 1) assert.Len(t, reasons, 1)
resp, err = r.KillJob(job.JobKey()) _, err = r.KillJob(job.JobKey())
assert.NoError(t, err) assert.NoError(t, err)
} }
@ -379,7 +396,7 @@ func TestRealisClient_CreateService_WithPulse_Thermos(t *testing.T) {
job.InstanceCount(2) job.InstanceCount(2)
_, result, err := r.CreateService(job, settings) _, result, err := r.CreateService(job, settings)
assert.NoError(t, err) require.NoError(t, err)
updateQ := aurora.JobUpdateQuery{ updateQ := aurora.JobUpdateQuery{
Key: result.GetKey(), Key: result.GetKey(),
@ -399,13 +416,13 @@ pulseLoop:
case <-ticker.C: case <-ticker.C:
_, err = r.PulseJobUpdate(result.GetKey()) _, err = r.PulseJobUpdate(result.GetKey())
assert.Nil(t, err, "unable to pulse job update") assert.NoError(t, err, "unable to pulse job update")
respDetail, err := r.JobUpdateDetails(updateQ) respDetail, err := r.JobUpdateDetails(updateQ)
assert.Nil(t, err) assert.NoError(t, err)
updateDetails = response.JobUpdateDetails(respDetail) updateDetails = response.JobUpdateDetails(respDetail)
assert.Len(t, updateDetails, 1, "No update found") require.Len(t, updateDetails, 1, "No update found")
status := updateDetails[0].Update.Summary.State.Status status := updateDetails[0].Update.Summary.State.Status
if _, ok := realis.ActiveJobUpdateStates[status]; !ok { if _, ok := realis.ActiveJobUpdateStates[status]; !ok {
@ -424,7 +441,8 @@ pulseLoop:
_, err := r.AbortJobUpdate(*updateDetails[0].GetUpdate().GetSummary().GetKey(), "") _, err := r.AbortJobUpdate(*updateDetails[0].GetUpdate().GetSummary().GetKey(), "")
assert.NoError(t, err) assert.NoError(t, err)
_, err = r.KillJob(job.JobKey()) _, err = r.KillJob(job.JobKey())
require.NoError(t, err, "timed out during pulse update test") assert.NoError(t, err, "timed out during pulse update test")
t.FailNow()
} }
} }
@ -454,7 +472,7 @@ func TestRealisClient_CreateService(t *testing.T) {
job.InstanceCount(3) job.InstanceCount(3)
_, result, err := r.CreateService(job, settings) _, result, err := r.CreateService(job, settings)
assert.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, result) assert.NotNil(t, result)
// Test asking the scheduler to backup a Snapshot // Test asking the scheduler to backup a Snapshot
@ -478,21 +496,24 @@ func TestRealisClient_CreateService(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
} }
require.NoError(t, mErr)
assert.True(t, ok) assert.True(t, ok)
assert.NoError(t, mErr)
// Kill task test task after confirming it came up fine // Kill task test task after confirming it came up fine
_, err = r.KillJob(job.JobKey()) _, err = r.KillJob(job.JobKey())
assert.NoError(t, err) assert.NoError(t, err)
success, err := monitor.Instances(job.JobKey(), 0, 1, 50) success, err := monitor.Instances(job.JobKey(), 0, 1, 50)
require.NoError(t, mErr)
assert.True(t, success) assert.True(t, success)
// Create a client which will timeout and close the connection before receiving an answer // Create a client which will timeout and close the connection before receiving an answer
timeoutClient, err := realis.NewRealisClient(realis.SchedulerUrl(auroraURL), timeoutClient, err := realis.NewRealisClient(
realis.SchedulerUrl(auroraURL),
realis.BasicAuth("aurora", "secret"), realis.BasicAuth("aurora", "secret"),
realis.TimeoutMS(10)) realis.TimeoutMS(10),
assert.NoError(t, err) )
require.NoError(t, err)
defer timeoutClient.Close() defer timeoutClient.Close()
// Test case where http connection timeouts out. // Test case where http connection timeouts out.
@ -501,7 +522,7 @@ func TestRealisClient_CreateService(t *testing.T) {
// Make sure a timedout error was returned // Make sure a timedout error was returned
_, _, err = timeoutClient.CreateService(job, settings) _, _, err = timeoutClient.CreateService(job, settings)
assert.Error(t, err) require.Error(t, err)
assert.True(t, realis.IsTimeout(err)) assert.True(t, realis.IsTimeout(err))
updateReceivedQuery := aurora.JobUpdateQuery{ updateReceivedQuery := aurora.JobUpdateQuery{
@ -511,11 +532,11 @@ func TestRealisClient_CreateService(t *testing.T) {
Limit: 1} Limit: 1}
updateSummaries, err := monitor.JobUpdateQuery(updateReceivedQuery, time.Second*1, time.Second*50) updateSummaries, err := monitor.JobUpdateQuery(updateReceivedQuery, time.Second*1, time.Second*50)
assert.NoError(t, err) require.NoError(t, err)
assert.Len(t, updateSummaries, 1) require.Len(t, updateSummaries, 1)
_, err = r.AbortJobUpdate(*updateSummaries[0].Key, "Cleaning up") r.AbortJobUpdate(*updateSummaries[0].Key, "Cleaning up")
_, err = r.KillJob(job.JobKey()) _, err = r.KillJob(job.JobKey())
assert.NoError(t, err) assert.NoError(t, err)
@ -529,7 +550,7 @@ func TestRealisClient_CreateService(t *testing.T) {
// Make sure a timedout error was returned // Make sure a timedout error was returned
_, _, err = timeoutClient.CreateService(job, settings) _, _, err = timeoutClient.CreateService(job, settings)
assert.Error(t, err) require.Error(t, err)
assert.True(t, realis.IsTimeout(err)) assert.True(t, realis.IsTimeout(err))
summary, err := r.GetJobUpdateSummaries( summary, err := r.GetJobUpdateSummaries(
@ -540,7 +561,7 @@ func TestRealisClient_CreateService(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
// Payload should have been rejected, no update should exist // Payload should have been rejected, no update should exist
assert.Len(t, summary.GetResult_().GetGetJobUpdateSummariesResult_().GetUpdateSummaries(), 0) require.Len(t, summary.GetResult_().GetGetJobUpdateSummariesResult_().GetUpdateSummaries(), 0)
}) })
} }
@ -563,9 +584,9 @@ func TestRealisClient_CreateService_ExecutorDoesNotExist(t *testing.T) {
job.InstanceCount(3) job.InstanceCount(3)
resp, result, err := r.CreateService(job, settings) resp, result, err := r.CreateService(job, settings)
assert.Error(t, err) require.Error(t, err)
assert.Nil(t, result) assert.Nil(t, result)
assert.Equal(t, aurora.ResponseCode_INVALID_REQUEST, resp.GetResponseCode()) require.Equal(t, aurora.ResponseCode_INVALID_REQUEST, resp.GetResponseCode())
} }
func TestRealisClient_ScheduleCronJob_Thermos(t *testing.T) { func TestRealisClient_ScheduleCronJob_Thermos(t *testing.T) {
@ -589,23 +610,23 @@ func TestRealisClient_ScheduleCronJob_Thermos(t *testing.T) {
IsService(false) IsService(false)
_, err = r.ScheduleCronJob(job) _, err = r.ScheduleCronJob(job)
assert.NoError(t, err) require.NoError(t, err)
t.Run("Start", func(t *testing.T) { t.Run("Start", func(t *testing.T) {
_, err := r.StartCronJob(job.JobKey()) _, err := r.StartCronJob(job.JobKey())
assert.NoError(t, err) require.NoError(t, err)
}) })
t.Run("Deschedule", func(t *testing.T) { t.Run("Deschedule", func(t *testing.T) {
_, err := r.DescheduleCronJob(job.JobKey()) _, err := r.DescheduleCronJob(job.JobKey())
assert.NoError(t, err) require.NoError(t, err)
}) })
} }
func TestRealisClient_StartMaintenance(t *testing.T) { func TestRealisClient_StartMaintenance(t *testing.T) {
hosts := []string{"localhost"} hosts := []string{"localhost"}
_, _, err := r.StartMaintenance(hosts...) _, _, err := r.StartMaintenance(hosts...)
assert.NoError(t, err, "unable to start maintenance") require.NoError(t, err, "unable to start maintenance")
// Monitor change to DRAINING and DRAINED mode // Monitor change to DRAINING and DRAINED mode
hostResults, err := monitor.HostMaintenance( hostResults, err := monitor.HostMaintenance(
@ -613,11 +634,11 @@ func TestRealisClient_StartMaintenance(t *testing.T) {
[]aurora.MaintenanceMode{aurora.MaintenanceMode_SCHEDULED}, []aurora.MaintenanceMode{aurora.MaintenanceMode_SCHEDULED},
1, 1,
50) 50)
assert.Equal(t, map[string]bool{"localhost": true}, hostResults)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, map[string]bool{"localhost": true}, hostResults)
_, _, err = r.EndMaintenance(hosts...) _, _, err = r.EndMaintenance(hosts...)
assert.NoError(t, err) require.NoError(t, err)
// Monitor change to DRAINING and DRAINED mode // Monitor change to DRAINING and DRAINED mode
_, err = monitor.HostMaintenance( _, err = monitor.HostMaintenance(
@ -643,8 +664,8 @@ func TestRealisClient_DrainHosts(t *testing.T) {
[]aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED, aurora.MaintenanceMode_DRAINING}, []aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED, aurora.MaintenanceMode_DRAINING},
1, 1,
50) 50)
require.NoError(t, err)
assert.Equal(t, map[string]bool{"localhost": true}, hostResults) assert.Equal(t, map[string]bool{"localhost": true}, hostResults)
assert.NoError(t, err)
}) })
t.Run("MonitorNonExistentHost", func(t *testing.T) { t.Run("MonitorNonExistentHost", func(t *testing.T) {
@ -656,13 +677,13 @@ func TestRealisClient_DrainHosts(t *testing.T) {
1) 1)
// Assert monitor returned an error that was not nil, and also a list of the non-transitioned hosts // Assert monitor returned an error that was not nil, and also a list of the non-transitioned hosts
assert.Error(t, err) require.Error(t, err)
assert.Equal(t, map[string]bool{"localhost": true, "IMAGINARY_HOST": false}, hostResults) assert.Equal(t, map[string]bool{"localhost": true, "IMAGINARY_HOST": false}, hostResults)
}) })
t.Run("EndMaintenance", func(t *testing.T) { t.Run("EndMaintenance", func(t *testing.T) {
_, _, err := r.EndMaintenance(hosts...) _, _, err := r.EndMaintenance(hosts...)
assert.NoError(t, err) require.NoError(t, err)
// Monitor change to DRAINING and DRAINED mode // Monitor change to DRAINING and DRAINED mode
_, err = monitor.HostMaintenance( _, err = monitor.HostMaintenance(
@ -680,7 +701,7 @@ func TestRealisClient_SLADrainHosts(t *testing.T) {
policy := aurora.SlaPolicy{PercentageSlaPolicy: &aurora.PercentageSlaPolicy{Percentage: 50.0}} policy := aurora.SlaPolicy{PercentageSlaPolicy: &aurora.PercentageSlaPolicy{Percentage: 50.0}}
_, err := r.SLADrainHosts(&policy, 30, hosts...) _, err := r.SLADrainHosts(&policy, 30, hosts...)
assert.NoError(t, err, "unable to drain host with SLA policy") require.NoError(t, err, "unable to drain host with SLA policy")
// Monitor change to DRAINING and DRAINED mode // Monitor change to DRAINING and DRAINED mode
hostResults, err := monitor.HostMaintenance( hostResults, err := monitor.HostMaintenance(
@ -688,11 +709,11 @@ func TestRealisClient_SLADrainHosts(t *testing.T) {
[]aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED, aurora.MaintenanceMode_DRAINING}, []aurora.MaintenanceMode{aurora.MaintenanceMode_DRAINED, aurora.MaintenanceMode_DRAINING},
1, 1,
50) 50)
assert.Equal(t, map[string]bool{"localhost": true}, hostResults)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, map[string]bool{"localhost": true}, hostResults)
_, _, err = r.EndMaintenance(hosts...) _, _, err = r.EndMaintenance(hosts...)
assert.NoError(t, err) require.NoError(t, err)
// Monitor change to DRAINING and DRAINED mode // Monitor change to DRAINING and DRAINED mode
_, err = monitor.HostMaintenance( _, err = monitor.HostMaintenance(
@ -770,13 +791,10 @@ func TestRealisClient_Quota(t *testing.T) {
switch true { switch true {
case res.DiskMb != nil: case res.DiskMb != nil:
assert.Equal(t, disk, *res.DiskMb) assert.Equal(t, disk, *res.DiskMb)
break
case res.NumCpus != nil: case res.NumCpus != nil:
assert.Equal(t, cpu, *res.NumCpus) assert.Equal(t, cpu, *res.NumCpus)
break
case res.RamMb != nil: case res.RamMb != nil:
assert.Equal(t, ram, *res.RamMb) assert.Equal(t, ram, *res.RamMb)
break
} }
} }
}) })
@ -829,7 +847,7 @@ func TestRealisClient_PartitionPolicy(t *testing.T) {
} }
// Clean up after finishing test // Clean up after finishing test
_, err = r.KillJob(job.JobKey()) r.KillJob(job.JobKey())
} }
func TestAuroraJob_UpdateSlaPolicy(t *testing.T) { func TestAuroraJob_UpdateSlaPolicy(t *testing.T) {
@ -880,7 +898,7 @@ func TestAuroraJob_UpdateSlaPolicy(t *testing.T) {
settings.MinWaitInInstanceRunningMs = 5 * 1000 settings.MinWaitInInstanceRunningMs = 5 * 1000
_, result, err := r.CreateService(job, settings) _, result, err := r.CreateService(job, settings)
assert.NoError(t, err) require.NoError(t, err)
assert.NotNil(t, result) assert.NotNil(t, result)
var ok bool var ok bool
@ -894,8 +912,8 @@ func TestAuroraJob_UpdateSlaPolicy(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
} }
assert.True(t, ok)
assert.NoError(t, mErr) assert.NoError(t, mErr)
assert.True(t, ok)
// Kill task test task after confirming it came up fine // Kill task test task after confirming it came up fine
_, err = r.KillJob(job.JobKey()) _, err = r.KillJob(job.JobKey())

View file

@ -77,7 +77,8 @@ func ExponentialBackoff(backoff Backoff, logger Logger, condition ConditionFunc)
adjusted = Jitter(duration, backoff.Jitter) adjusted = Jitter(duration, backoff.Jitter)
} }
logger.Printf("A retryable error occurred during function call, backing off for %v before retrying\n", adjusted) logger.Printf(
"A retryable error occurred during function call, backing off for %v before retrying\n", adjusted)
time.Sleep(adjusted) time.Sleep(adjusted)
duration = time.Duration(float64(duration) * backoff.Factor) duration = time.Duration(float64(duration) * backoff.Factor)
} }
@ -116,7 +117,10 @@ func ExponentialBackoff(backoff Backoff, logger Logger, condition ConditionFunc)
type auroraThriftCall func() (resp *aurora.Response, err error) type auroraThriftCall func() (resp *aurora.Response, err error)
// Duplicates the functionality of ExponentialBackoff but is specifically targeted towards ThriftCalls. // Duplicates the functionality of ExponentialBackoff but is specifically targeted towards ThriftCalls.
func (r *realisClient) thriftCallWithRetries(returnOnTimeout bool, thriftCall auroraThriftCall) (*aurora.Response, error) { func (r *realisClient) thriftCallWithRetries(
returnOnTimeout bool,
thriftCall auroraThriftCall) (*aurora.Response, error) {
var resp *aurora.Response var resp *aurora.Response
var clientErr error var clientErr error
var curStep int var curStep int
@ -134,7 +138,10 @@ func (r *realisClient) thriftCallWithRetries(returnOnTimeout bool, thriftCall au
adjusted = Jitter(duration, backoff.Jitter) adjusted = Jitter(duration, backoff.Jitter)
} }
r.logger.Printf("A retryable error occurred during thrift call, backing off for %v before retry %v\n", adjusted, curStep) r.logger.Printf(
"A retryable error occurred during thrift call, backing off for %v before retry %v\n",
adjusted,
curStep)
time.Sleep(adjusted) time.Sleep(adjusted)
duration = time.Duration(float64(duration) * backoff.Factor) duration = time.Duration(float64(duration) * backoff.Factor)
@ -166,10 +173,11 @@ func (r *realisClient) thriftCallWithRetries(returnOnTimeout bool, thriftCall au
e, ok := e.Err().(*url.Error) e, ok := e.Err().(*url.Error)
if ok { if ok {
// EOF error occurs when the server closes the read buffer of the client. This is common // EOF error occurs when the server closes the read buffer of the client. This is common
// when the server is overloaded and should be retried. All other errors that are permanent // when the server is overloaded and should be retried. All other errors that are permanent
// will not be retried. // will not be retried.
if e.Err != io.EOF && !e.Temporary() { if e.Err != io.EOF && !e.Temporary() && r.RealisConfig().failOnPermanentErrors {
return nil, errors.Wrap(clientErr, "permanent connection error") return nil, errors.Wrap(clientErr, "permanent connection error")
} }
@ -179,7 +187,8 @@ func (r *realisClient) thriftCallWithRetries(returnOnTimeout bool, thriftCall au
if e.Timeout() { if e.Timeout() {
timeouts++ timeouts++
r.logger.DebugPrintf( r.logger.DebugPrintf(
"Client closed connection (timedout) %d times before server responded, consider increasing connection timeout", "Client closed connection (timedout) %d times before server responded, "+
"consider increasing connection timeout",
timeouts) timeouts)
if returnOnTimeout { if returnOnTimeout {
return resp, newTimedoutError(errors.New("client connection closed before server answer")) return resp, newTimedoutError(errors.New("client connection closed before server answer"))
@ -190,7 +199,8 @@ func (r *realisClient) thriftCallWithRetries(returnOnTimeout bool, thriftCall au
// In the future, reestablish connection should be able to check if it is actually possible // In the future, reestablish connection should be able to check if it is actually possible
// to make a thrift call to Aurora. For now, a reconnect should always lead to a retry. // to make a thrift call to Aurora. For now, a reconnect should always lead to a retry.
r.ReestablishConn() // Ignoring error due to the fact that an error should be retried regardless
_ = r.ReestablishConn()
} else { } else {

View file

@ -31,7 +31,12 @@ func NewDefaultUpdateJob(config *aurora.TaskConfig) *UpdateJob {
req.TaskConfig = config req.TaskConfig = config
req.Settings = NewUpdateSettings() req.Settings = NewUpdateSettings()
job := NewJob().(*AuroraJob) job, ok := NewJob().(*AuroraJob)
if !ok {
// This should never happen but it is here as a safeguard
return nil
}
job.jobConfig.TaskConfig = config job.jobConfig.TaskConfig = config
// Rebuild resource map from TaskConfig // Rebuild resource map from TaskConfig
@ -75,7 +80,11 @@ func NewUpdateJob(config *aurora.TaskConfig, settings *aurora.JobUpdateSettings)
req.TaskConfig = config req.TaskConfig = config
req.Settings = settings req.Settings = settings
job := NewJob().(*AuroraJob) job, ok := NewJob().(*AuroraJob)
if !ok {
// This should never happen but it is here as a safeguard
return nil
}
job.jobConfig.TaskConfig = config job.jobConfig.TaskConfig = config
// Rebuild resource map from TaskConfig // Rebuild resource map from TaskConfig

13
util.go
View file

@ -8,6 +8,8 @@ import (
"github.com/pkg/errors" "github.com/pkg/errors"
) )
const apiPath = "/api"
var ActiveStates = make(map[aurora.ScheduleStatus]bool) var ActiveStates = make(map[aurora.ScheduleStatus]bool)
var SlaveAssignedStates = make(map[aurora.ScheduleStatus]bool) var SlaveAssignedStates = make(map[aurora.ScheduleStatus]bool)
var LiveStates = make(map[aurora.ScheduleStatus]bool) var LiveStates = make(map[aurora.ScheduleStatus]bool)
@ -40,14 +42,14 @@ func init() {
} }
} }
func validateAndPopulateAuroraURL(urlStr string) (string, error) { func validateAuroraURL(location string) (string, error) {
// If no protocol defined, assume http // If no protocol defined, assume http
if !strings.Contains(urlStr, "://") { if !strings.Contains(location, "://") {
urlStr = "http://" + urlStr location = "http://" + location
} }
u, err := url.Parse(urlStr) u, err := url.Parse(location)
if err != nil { if err != nil {
return "", errors.Wrap(err, "error parsing url") return "", errors.Wrap(err, "error parsing url")
@ -67,7 +69,8 @@ func validateAndPopulateAuroraURL(urlStr string) (string, error) {
return "", errors.Errorf("only protocols http and https are supported %v\n", u.Scheme) return "", errors.Errorf("only protocols http and https are supported %v\n", u.Scheme)
} }
if u.Path != "/api" { // This could theoretically be elsewhwere but we'll be strict for the sake of simplicty
if u.Path != apiPath {
return "", errors.Errorf("expected /api path %v\n", u.Path) return "", errors.Errorf("expected /api path %v\n", u.Path)
} }

65
util_test.go Normal file
View file

@ -0,0 +1,65 @@
/**
* 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 realis
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestAuroraURLValidator(t *testing.T) {
t.Run("badURL", func(t *testing.T) {
url, err := validateAuroraURL("http://badurl.com/badpath")
assert.Empty(t, url)
assert.Error(t, err)
})
t.Run("URLHttp", func(t *testing.T) {
url, err := validateAuroraURL("http://goodurl.com:8081/api")
assert.Equal(t, "http://goodurl.com:8081/api", url)
assert.NoError(t, err)
})
t.Run("URLHttps", func(t *testing.T) {
url, err := validateAuroraURL("https://goodurl.com:8081/api")
assert.Equal(t, "https://goodurl.com:8081/api", url)
assert.NoError(t, err)
})
t.Run("URLNoPath", func(t *testing.T) {
url, err := validateAuroraURL("http://goodurl.com:8081")
assert.Equal(t, "http://goodurl.com:8081/api", url)
assert.NoError(t, err)
})
t.Run("ipAddrNoPath", func(t *testing.T) {
url, err := validateAuroraURL("http://192.168.1.33:8081")
assert.Equal(t, "http://192.168.1.33:8081/api", url)
assert.NoError(t, err)
})
t.Run("URLNoProtocol", func(t *testing.T) {
url, err := validateAuroraURL("goodurl.com:8081/api")
assert.Equal(t, "http://goodurl.com:8081/api", url)
assert.NoError(t, err)
})
t.Run("URLNoProtocolNoPathNoPort", func(t *testing.T) {
url, err := validateAuroraURL("goodurl.com")
assert.Equal(t, "http://goodurl.com:8081/api", url)
assert.NoError(t, err)
})
}

View file

@ -2,14 +2,18 @@ language: go
sudo: false sudo: false
go: matrix:
- 1.7 include:
- 1.8 - go: "1.8.x"
- 1.9 - go: "1.9.x"
- tip - go: "1.10.x"
- go: "1.11.x"
script: env: GO111MODULE=off
- ./.travis.gogenerate.sh - go: "1.11.x"
- ./.travis.gofmt.sh env: GO111MODULE=on
- ./.travis.govet.sh - go: tip
- go test -v -race ./... script:
- ./.travis.gogenerate.sh
- ./.travis.gofmt.sh
- ./.travis.govet.sh
- go test -v -race $(go list ./... | grep -v vendor)

View file

@ -10,16 +10,18 @@
[[projects]] [[projects]]
name = "github.com/pmezard/go-difflib" name = "github.com/pmezard/go-difflib"
packages = ["difflib"] packages = ["difflib"]
revision = "d8ed2627bdf02c080bf22230dbb337003b7aba2d" revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]] [[projects]]
name = "github.com/stretchr/objx" name = "github.com/stretchr/objx"
packages = ["."] packages = ["."]
revision = "cbeaeb16a013161a98496fad62933b1d21786672" revision = "facf9a85c22f48d2f52f2380e4efce1768749a89"
version = "v0.1"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
inputs-digest = "6bd8fb1f11a0d3df245fc01bd8853f6dac40b83457e780f7978ca30244647c7b" inputs-digest = "448ddae4702c6aded2555faafd390c537789bb1c483f70b0431e6634f73f2090"
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View file

@ -1,26 +1,16 @@
[prune]
# Gopkg.toml example unused-packages = true
# non-go = true
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md go-tests = true
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
[[constraint]] [[constraint]]
name = "github.com/davecgh/go-spew" name = "github.com/davecgh/go-spew"
version = ">=1.0.0, <=3.0.0-g6d21280" version = "~1.1.0"
[[constraint]]
name = "github.com/pmezard/go-difflib"
version = "~1.0.0"
[[constraint]]
name = "github.com/stretchr/objx"
version = "~0.1.0"

View file

@ -1,22 +1,21 @@
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell MIT License
Please consider promoting this project if you find it useful. Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
Permission is hereby granted, free of charge, to any person Permission is hereby granted, free of charge, to any person obtaining a copy
obtaining a copy of this software and associated documentation of this software and associated documentation files (the "Software"), to deal
files (the "Software"), to deal in the Software without restriction, in the Software without restriction, including without limitation the rights
including without limitation the rights to use, copy, modify, merge, to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
publish, distribute, sublicense, and/or sell copies of the Software, copies of the Software, and to permit persons to whom the Software is
and to permit persons to whom the Software is furnished to do so, furnished to do so, subject to the following conditions:
subject to the following conditions:
The above copyright notice and this permission notice shall be included The above copyright notice and this permission notice shall be included in all
in all copies or substantial portions of the Software. copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE.

View file

@ -9,7 +9,6 @@ Features include:
* [Easy assertions](#assert-package) * [Easy assertions](#assert-package)
* [Mocking](#mock-package) * [Mocking](#mock-package)
* [HTTP response trapping](#http-package)
* [Testing suite interfaces and functions](#suite-package) * [Testing suite interfaces and functions](#suite-package)
Get started: Get started:
@ -106,14 +105,6 @@ The `require` package provides same global functions as the `assert` package, bu
See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details. See [t.FailNow](http://golang.org/pkg/testing/#T.FailNow) for details.
[`http`](http://godoc.org/github.com/stretchr/testify/http "API documentation") package
---------------------------------------------------------------------------------------
The `http` package contains test objects useful for testing code that relies on the `net/http` package. Check out the [(deprecated) API documentation for the `http` package](http://godoc.org/github.com/stretchr/testify/http).
We recommend you use [httptest](http://golang.org/pkg/net/http/httptest) instead.
[`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package [`mock`](http://godoc.org/github.com/stretchr/testify/mock "API documentation") package
---------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------
@ -173,6 +164,29 @@ func TestSomething(t *testing.T) {
// assert that the expectations were met // assert that the expectations were met
testObj.AssertExpectations(t) testObj.AssertExpectations(t)
}
// TestSomethingElse is a second example of how to use our test object to
// make assertions about some target code we are testing.
// This time using a placeholder. Placeholders might be used when the
// data being passed in is normally dynamically generated and cannot be
// predicted beforehand (eg. containing hashes that are time sensitive)
func TestSomethingElse(t *testing.T) {
// create an instance of our test object
testObj := new(MyMockedObject)
// setup expectations with a placeholder in the argument list
testObj.On("DoSomething", mock.Anything).Return(true, nil)
// call the code we are testing
targetFuncThatDoesSomethingWithObj(testObj)
// assert that the expectations were met
testObj.AssertExpectations(t)
} }
``` ```
@ -268,14 +282,15 @@ Installation
To install Testify, use `go get`: To install Testify, use `go get`:
* Latest version: go get github.com/stretchr/testify go get github.com/stretchr/testify
* Specific version: go get gopkg.in/stretchr/testify.v1
This will then make the following packages available to you: This will then make the following packages available to you:
github.com/stretchr/testify/assert github.com/stretchr/testify/assert
github.com/stretchr/testify/require
github.com/stretchr/testify/mock github.com/stretchr/testify/mock
github.com/stretchr/testify/http github.com/stretchr/testify/suite
github.com/stretchr/testify/http (deprecated)
Import the `testify/assert` package into your code using this template: Import the `testify/assert` package into your code using this template:
@ -303,10 +318,10 @@ To update Testify to the latest version, use `go get -u github.com/stretchr/test
------ ------
Version History Supported go versions
=============== ==================
* 1.0 - New package versioning strategy adopted. We support the three major Go versions, which are 1.9, 1.10, and 1.11 at the moment.
------ ------
@ -319,14 +334,7 @@ When submitting an issue, we ask that you please include a complete test functio
------ ------
Licence License
======= =======
Copyright (c) 2012 - 2013 Mat Ryer and Tyler Bunnell
Please consider promoting this project if you find it useful. This project is licensed under the terms of the MIT license.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -13,6 +13,9 @@ import (
// Conditionf uses a Comparison to assert a complex condition. // Conditionf uses a Comparison to assert a complex condition.
func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool { func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Condition(t, comp, append([]interface{}{msg}, args...)...) return Condition(t, comp, append([]interface{}{msg}, args...)...)
} }
@ -22,14 +25,18 @@ func Conditionf(t TestingT, comp Comparison, msg string, args ...interface{}) bo
// assert.Containsf(t, "Hello World", "World", "error message %s", "formatted") // assert.Containsf(t, "Hello World", "World", "error message %s", "formatted")
// assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted") // assert.Containsf(t, ["Hello", "World"], "World", "error message %s", "formatted")
// assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted") // assert.Containsf(t, {"Hello": "World"}, "Hello", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Contains(t, s, contains, append([]interface{}{msg}, args...)...) return Contains(t, s, contains, append([]interface{}{msg}, args...)...)
} }
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. // DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool { func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return DirExists(t, path, append([]interface{}{msg}, args...)...) return DirExists(t, path, append([]interface{}{msg}, args...)...)
} }
@ -37,10 +44,11 @@ func DirExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match. // the number of appearances of each of them in both lists should match.
// //
// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")) // assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool { func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...) return ElementsMatch(t, listA, listB, append([]interface{}{msg}, args...)...)
} }
@ -48,9 +56,10 @@ func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// assert.Emptyf(t, obj, "error message %s", "formatted") // assert.Emptyf(t, obj, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Empty(t, object, append([]interface{}{msg}, args...)...) return Empty(t, object, append([]interface{}{msg}, args...)...)
} }
@ -58,12 +67,13 @@ func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) boo
// //
// assert.Equalf(t, 123, 123, "error message %s", "formatted") // assert.Equalf(t, 123, 123, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail. // cannot be determined and will always fail.
func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Equal(t, expected, actual, append([]interface{}{msg}, args...)...) return Equal(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
@ -72,9 +82,10 @@ func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, ar
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") // assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool { func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...) return EqualError(t, theError, errString, append([]interface{}{msg}, args...)...)
} }
@ -82,9 +93,10 @@ func EqualErrorf(t TestingT, theError error, errString string, msg string, args
// and equal. // and equal.
// //
// assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123)) // assert.EqualValuesf(t, uint32(123, "error message %s", "formatted"), int32(123))
//
// Returns whether the assertion was successful (true) or not (false).
func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...) return EqualValues(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
@ -94,62 +106,80 @@ func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg stri
// if assert.Errorf(t, err, "error message %s", "formatted") { // if assert.Errorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err) // assert.Equal(t, expectedErrorf, err)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func Errorf(t TestingT, err error, msg string, args ...interface{}) bool { func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Error(t, err, append([]interface{}{msg}, args...)...) return Error(t, err, append([]interface{}{msg}, args...)...)
} }
// Exactlyf asserts that two objects are equal in value and type. // Exactlyf asserts that two objects are equal in value and type.
// //
// assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123)) // assert.Exactlyf(t, int32(123, "error message %s", "formatted"), int64(123))
//
// Returns whether the assertion was successful (true) or not (false).
func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...) return Exactly(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
// Failf reports a failure through // Failf reports a failure through
func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Fail(t, failureMessage, append([]interface{}{msg}, args...)...) return Fail(t, failureMessage, append([]interface{}{msg}, args...)...)
} }
// FailNowf fails test // FailNowf fails test
func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool { func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...) return FailNow(t, failureMessage, append([]interface{}{msg}, args...)...)
} }
// Falsef asserts that the specified value is false. // Falsef asserts that the specified value is false.
// //
// assert.Falsef(t, myBool, "error message %s", "formatted") // assert.Falsef(t, myBool, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool { func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return False(t, value, append([]interface{}{msg}, args...)...) return False(t, value, append([]interface{}{msg}, args...)...)
} }
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. // FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool { func FileExistsf(t TestingT, path string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return FileExists(t, path, append([]interface{}{msg}, args...)...) return FileExists(t, path, append([]interface{}{msg}, args...)...)
} }
// HTTPBodyContainsf asserts that a specified handler returns a // HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// assert.HTTPBodyContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // assert.HTTPBodyContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) return HTTPBodyContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
} }
// HTTPBodyNotContainsf asserts that a specified handler returns a // HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// assert.HTTPBodyNotContainsf(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // assert.HTTPBodyNotContainsf(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...) return HTTPBodyNotContains(t, handler, method, url, values, str, append([]interface{}{msg}, args...)...)
} }
@ -159,6 +189,9 @@ func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, u
// //
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). // Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...) return HTTPError(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
} }
@ -168,6 +201,9 @@ func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string,
// //
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). // Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...) return HTTPRedirect(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
} }
@ -177,6 +213,9 @@ func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url stri
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...) return HTTPSuccess(t, handler, method, url, values, append([]interface{}{msg}, args...)...)
} }
@ -184,51 +223,69 @@ func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, url strin
// //
// assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) // assert.Implementsf(t, (*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...) return Implements(t, interfaceObject, object, append([]interface{}{msg}, args...)...)
} }
// InDeltaf asserts that the two numerals are within delta of each other. // InDeltaf asserts that the two numerals are within delta of each other.
// //
// assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) // assert.InDeltaf(t, math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...) return InDelta(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
} }
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func InDeltaMapValuesf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...) return InDeltaMapValues(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
} }
// InDeltaSlicef is the same as InDelta, except it compares two slices. // InDeltaSlicef is the same as InDelta, except it compares two slices.
func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func InDeltaSlicef(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...) return InDeltaSlice(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
} }
// InEpsilonf asserts that expected and actual have a relative error less than epsilon // InEpsilonf asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) return InEpsilon(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
} }
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...) return InEpsilonSlice(t, expected, actual, epsilon, append([]interface{}{msg}, args...)...)
} }
// IsTypef asserts that the specified objects are of the same type. // IsTypef asserts that the specified objects are of the same type.
func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...) return IsType(t, expectedType, object, append([]interface{}{msg}, args...)...)
} }
// JSONEqf asserts that two JSON strings are equivalent. // JSONEqf asserts that two JSON strings are equivalent.
// //
// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") // assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool { func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...) return JSONEq(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
@ -236,18 +293,20 @@ func JSONEqf(t TestingT, expected string, actual string, msg string, args ...int
// Lenf also fails if the object has a type that len() not accept. // Lenf also fails if the object has a type that len() not accept.
// //
// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") // assert.Lenf(t, mySlice, 3, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool { func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Len(t, object, length, append([]interface{}{msg}, args...)...) return Len(t, object, length, append([]interface{}{msg}, args...)...)
} }
// Nilf asserts that the specified object is nil. // Nilf asserts that the specified object is nil.
// //
// assert.Nilf(t, err, "error message %s", "formatted") // assert.Nilf(t, err, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Nil(t, object, append([]interface{}{msg}, args...)...) return Nil(t, object, append([]interface{}{msg}, args...)...)
} }
@ -257,9 +316,10 @@ func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) bool
// if assert.NoErrorf(t, err, "error message %s", "formatted") { // if assert.NoErrorf(t, err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool { func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NoError(t, err, append([]interface{}{msg}, args...)...) return NoError(t, err, append([]interface{}{msg}, args...)...)
} }
@ -269,9 +329,10 @@ func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bool {
// assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted") // assert.NotContainsf(t, "Hello World", "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted") // assert.NotContainsf(t, ["Hello", "World"], "Earth", "error message %s", "formatted")
// assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted") // assert.NotContainsf(t, {"Hello": "World"}, "Earth", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool { func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotContains(t, s, contains, append([]interface{}{msg}, args...)...) return NotContains(t, s, contains, append([]interface{}{msg}, args...)...)
} }
@ -281,9 +342,10 @@ func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, a
// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { // if assert.NotEmptyf(t, obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEmpty(t, object, append([]interface{}{msg}, args...)...) return NotEmpty(t, object, append([]interface{}{msg}, args...)...)
} }
@ -291,29 +353,32 @@ func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{})
// //
// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") // assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...) return NotEqual(t, expected, actual, append([]interface{}{msg}, args...)...)
} }
// NotNilf asserts that the specified object is not nil. // NotNilf asserts that the specified object is not nil.
// //
// assert.NotNilf(t, err, "error message %s", "formatted") // assert.NotNilf(t, err, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool { func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotNil(t, object, append([]interface{}{msg}, args...)...) return NotNil(t, object, append([]interface{}{msg}, args...)...)
} }
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") // assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotPanics(t, f, append([]interface{}{msg}, args...)...) return NotPanics(t, f, append([]interface{}{msg}, args...)...)
} }
@ -321,9 +386,10 @@ func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bo
// //
// assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") // assert.NotRegexpf(t, regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") // assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...) return NotRegexp(t, rx, str, append([]interface{}{msg}, args...)...)
} }
@ -331,23 +397,28 @@ func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ..
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") // assert.NotSubsetf(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...) return NotSubset(t, list, subset, append([]interface{}{msg}, args...)...)
} }
// NotZerof asserts that i is not the zero value for its type and returns the truth. // NotZerof asserts that i is not the zero value for its type.
func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return NotZero(t, i, append([]interface{}{msg}, args...)...) return NotZero(t, i, append([]interface{}{msg}, args...)...)
} }
// Panicsf asserts that the code inside the specified PanicTestFunc panics. // Panicsf asserts that the code inside the specified PanicTestFunc panics.
// //
// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") // assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool { func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Panics(t, f, append([]interface{}{msg}, args...)...) return Panics(t, f, append([]interface{}{msg}, args...)...)
} }
@ -355,9 +426,10 @@ func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{}) bool
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") // assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...) return PanicsWithValue(t, expected, f, append([]interface{}{msg}, args...)...)
} }
@ -365,9 +437,10 @@ func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc, msg str
// //
// assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") // assert.Regexpf(t, regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") // assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool { func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Regexp(t, rx, str, append([]interface{}{msg}, args...)...) return Regexp(t, rx, str, append([]interface{}{msg}, args...)...)
} }
@ -375,31 +448,37 @@ func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...in
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") // assert.Subsetf(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool { func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Subset(t, list, subset, append([]interface{}{msg}, args...)...) return Subset(t, list, subset, append([]interface{}{msg}, args...)...)
} }
// Truef asserts that the specified value is true. // Truef asserts that the specified value is true.
// //
// assert.Truef(t, myBool, "error message %s", "formatted") // assert.Truef(t, myBool, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func Truef(t TestingT, value bool, msg string, args ...interface{}) bool { func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return True(t, value, append([]interface{}{msg}, args...)...) return True(t, value, append([]interface{}{msg}, args...)...)
} }
// WithinDurationf asserts that the two times are within duration delta of each other. // WithinDurationf asserts that the two times are within duration delta of each other.
// //
// assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") // assert.WithinDurationf(t, time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...) return WithinDuration(t, expected, actual, delta, append([]interface{}{msg}, args...)...)
} }
// Zerof asserts that i is the zero value for its type and returns the truth. // Zerof asserts that i is the zero value for its type.
func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool { func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
return Zero(t, i, append([]interface{}{msg}, args...)...) return Zero(t, i, append([]interface{}{msg}, args...)...)
} }

View file

@ -1,4 +1,5 @@
{{.CommentFormat}} {{.CommentFormat}}
func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {
if h, ok := t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}})
} }

View file

@ -13,11 +13,17 @@ import (
// Condition uses a Comparison to assert a complex condition. // Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool { func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Condition(a.t, comp, msgAndArgs...) return Condition(a.t, comp, msgAndArgs...)
} }
// Conditionf uses a Comparison to assert a complex condition. // Conditionf uses a Comparison to assert a complex condition.
func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool { func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Conditionf(a.t, comp, msg, args...) return Conditionf(a.t, comp, msg, args...)
} }
@ -27,9 +33,10 @@ func (a *Assertions) Conditionf(comp Comparison, msg string, args ...interface{}
// a.Contains("Hello World", "World") // a.Contains("Hello World", "World")
// a.Contains(["Hello", "World"], "World") // a.Contains(["Hello", "World"], "World")
// a.Contains({"Hello": "World"}, "Hello") // a.Contains({"Hello": "World"}, "Hello")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Contains(a.t, s, contains, msgAndArgs...) return Contains(a.t, s, contains, msgAndArgs...)
} }
@ -39,19 +46,26 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ..
// a.Containsf("Hello World", "World", "error message %s", "formatted") // a.Containsf("Hello World", "World", "error message %s", "formatted")
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") // a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") // a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Containsf(a.t, s, contains, msg, args...) return Containsf(a.t, s, contains, msg, args...)
} }
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. // DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool { func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return DirExists(a.t, path, msgAndArgs...) return DirExists(a.t, path, msgAndArgs...)
} }
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. // DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool { func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return DirExistsf(a.t, path, msg, args...) return DirExistsf(a.t, path, msg, args...)
} }
@ -59,10 +73,11 @@ func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) bo
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match. // the number of appearances of each of them in both lists should match.
// //
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])) // a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ElementsMatch(a.t, listA, listB, msgAndArgs...) return ElementsMatch(a.t, listA, listB, msgAndArgs...)
} }
@ -70,10 +85,11 @@ func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndA
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match. // the number of appearances of each of them in both lists should match.
// //
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")) // a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool { func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return ElementsMatchf(a.t, listA, listB, msg, args...) return ElementsMatchf(a.t, listA, listB, msg, args...)
} }
@ -81,9 +97,10 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// a.Empty(obj) // a.Empty(obj)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Empty(a.t, object, msgAndArgs...) return Empty(a.t, object, msgAndArgs...)
} }
@ -91,9 +108,10 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) bool {
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// a.Emptyf(obj, "error message %s", "formatted") // a.Emptyf(obj, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Emptyf(a.t, object, msg, args...) return Emptyf(a.t, object, msg, args...)
} }
@ -101,12 +119,13 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{})
// //
// a.Equal(123, 123) // a.Equal(123, 123)
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail. // cannot be determined and will always fail.
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Equal(a.t, expected, actual, msgAndArgs...) return Equal(a.t, expected, actual, msgAndArgs...)
} }
@ -115,9 +134,10 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// a.EqualError(err, expectedErrorString) // a.EqualError(err, expectedErrorString)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool { func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualError(a.t, theError, errString, msgAndArgs...) return EqualError(a.t, theError, errString, msgAndArgs...)
} }
@ -126,9 +146,10 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") // a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool { func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualErrorf(a.t, theError, errString, msg, args...) return EqualErrorf(a.t, theError, errString, msg, args...)
} }
@ -136,9 +157,10 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a
// and equal. // and equal.
// //
// a.EqualValues(uint32(123), int32(123)) // a.EqualValues(uint32(123), int32(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualValues(a.t, expected, actual, msgAndArgs...) return EqualValues(a.t, expected, actual, msgAndArgs...)
} }
@ -146,9 +168,10 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
// and equal. // and equal.
// //
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123)) // a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return EqualValuesf(a.t, expected, actual, msg, args...) return EqualValuesf(a.t, expected, actual, msg, args...)
} }
@ -156,12 +179,13 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg
// //
// a.Equalf(123, 123, "error message %s", "formatted") // a.Equalf(123, 123, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail. // cannot be determined and will always fail.
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Equalf(a.t, expected, actual, msg, args...) return Equalf(a.t, expected, actual, msg, args...)
} }
@ -171,9 +195,10 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
// if a.Error(err) { // if a.Error(err) {
// assert.Equal(t, expectedError, err) // assert.Equal(t, expectedError, err)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool { func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Error(a.t, err, msgAndArgs...) return Error(a.t, err, msgAndArgs...)
} }
@ -183,115 +208,150 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
// if a.Errorf(err, "error message %s", "formatted") { // if a.Errorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err) // assert.Equal(t, expectedErrorf, err)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool { func (a *Assertions) Errorf(err error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Errorf(a.t, err, msg, args...) return Errorf(a.t, err, msg, args...)
} }
// Exactly asserts that two objects are equal in value and type. // Exactly asserts that two objects are equal in value and type.
// //
// a.Exactly(int32(123), int64(123)) // a.Exactly(int32(123), int64(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Exactly(a.t, expected, actual, msgAndArgs...) return Exactly(a.t, expected, actual, msgAndArgs...)
} }
// Exactlyf asserts that two objects are equal in value and type. // Exactlyf asserts that two objects are equal in value and type.
// //
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123)) // a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Exactlyf(a.t, expected, actual, msg, args...) return Exactlyf(a.t, expected, actual, msg, args...)
} }
// Fail reports a failure through // Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool { func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Fail(a.t, failureMessage, msgAndArgs...) return Fail(a.t, failureMessage, msgAndArgs...)
} }
// FailNow fails test // FailNow fails test
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool { func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FailNow(a.t, failureMessage, msgAndArgs...) return FailNow(a.t, failureMessage, msgAndArgs...)
} }
// FailNowf fails test // FailNowf fails test
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool { func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FailNowf(a.t, failureMessage, msg, args...) return FailNowf(a.t, failureMessage, msg, args...)
} }
// Failf reports a failure through // Failf reports a failure through
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool { func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Failf(a.t, failureMessage, msg, args...) return Failf(a.t, failureMessage, msg, args...)
} }
// False asserts that the specified value is false. // False asserts that the specified value is false.
// //
// a.False(myBool) // a.False(myBool)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool { func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return False(a.t, value, msgAndArgs...) return False(a.t, value, msgAndArgs...)
} }
// Falsef asserts that the specified value is false. // Falsef asserts that the specified value is false.
// //
// a.Falsef(myBool, "error message %s", "formatted") // a.Falsef(myBool, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool { func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Falsef(a.t, value, msg, args...) return Falsef(a.t, value, msg, args...)
} }
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. // FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool { func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FileExists(a.t, path, msgAndArgs...) return FileExists(a.t, path, msgAndArgs...)
} }
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. // FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool { func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return FileExistsf(a.t, path, msg, args...) return FileExistsf(a.t, path, msg, args...)
} }
// HTTPBodyContains asserts that a specified handler returns a // HTTPBodyContains asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") // a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) return HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
} }
// HTTPBodyContainsf asserts that a specified handler returns a // HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// a.HTTPBodyContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) return HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
} }
// HTTPBodyNotContains asserts that a specified handler returns a // HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") // a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) return HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
} }
// HTTPBodyNotContainsf asserts that a specified handler returns a // HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// a.HTTPBodyNotContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool { func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) return HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
} }
@ -301,6 +361,9 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPError(a.t, handler, method, url, values, msgAndArgs...) return HTTPError(a.t, handler, method, url, values, msgAndArgs...)
} }
@ -310,6 +373,9 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
// //
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). // Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPErrorf(a.t, handler, method, url, values, msg, args...) return HTTPErrorf(a.t, handler, method, url, values, msg, args...)
} }
@ -319,6 +385,9 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) return HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
} }
@ -328,6 +397,9 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
// //
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). // Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPRedirectf(a.t, handler, method, url, values, msg, args...) return HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
} }
@ -337,6 +409,9 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool { func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) return HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
} }
@ -346,6 +421,9 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool { func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return HTTPSuccessf(a.t, handler, method, url, values, msg, args...) return HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
} }
@ -353,6 +431,9 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s
// //
// a.Implements((*MyInterface)(nil), new(MyObject)) // a.Implements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Implements(a.t, interfaceObject, object, msgAndArgs...) return Implements(a.t, interfaceObject, object, msgAndArgs...)
} }
@ -360,96 +441,129 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
// //
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) // a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Implementsf(a.t, interfaceObject, object, msg, args...) return Implementsf(a.t, interfaceObject, object, msg, args...)
} }
// InDelta asserts that the two numerals are within delta of each other. // InDelta asserts that the two numerals are within delta of each other.
// //
// a.InDelta(math.Pi, (22 / 7.0), 0.01) // a.InDelta(math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDelta(a.t, expected, actual, delta, msgAndArgs...) return InDelta(a.t, expected, actual, delta, msgAndArgs...)
} }
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) return InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
} }
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) return InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
} }
// InDeltaSlice is the same as InDelta, except it compares two slices. // InDeltaSlice is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) return InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
} }
// InDeltaSlicef is the same as InDelta, except it compares two slices. // InDeltaSlicef is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaSlicef(a.t, expected, actual, delta, msg, args...) return InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
} }
// InDeltaf asserts that the two numerals are within delta of each other. // InDeltaf asserts that the two numerals are within delta of each other.
// //
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) // a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool { func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InDeltaf(a.t, expected, actual, delta, msg, args...) return InDeltaf(a.t, expected, actual, delta, msg, args...)
} }
// InEpsilon asserts that expected and actual have a relative error less than epsilon // InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) return InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
} }
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) return InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
} }
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) return InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
} }
// InEpsilonf asserts that expected and actual have a relative error less than epsilon // InEpsilonf asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool { func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return InEpsilonf(a.t, expected, actual, epsilon, msg, args...) return InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
} }
// IsType asserts that the specified objects are of the same type. // IsType asserts that the specified objects are of the same type.
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsType(a.t, expectedType, object, msgAndArgs...) return IsType(a.t, expectedType, object, msgAndArgs...)
} }
// IsTypef asserts that the specified objects are of the same type. // IsTypef asserts that the specified objects are of the same type.
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool { func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return IsTypef(a.t, expectedType, object, msg, args...) return IsTypef(a.t, expectedType, object, msg, args...)
} }
// JSONEq asserts that two JSON strings are equivalent. // JSONEq asserts that two JSON strings are equivalent.
// //
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool { func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return JSONEq(a.t, expected, actual, msgAndArgs...) return JSONEq(a.t, expected, actual, msgAndArgs...)
} }
// JSONEqf asserts that two JSON strings are equivalent. // JSONEqf asserts that two JSON strings are equivalent.
// //
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") // a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool { func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return JSONEqf(a.t, expected, actual, msg, args...) return JSONEqf(a.t, expected, actual, msg, args...)
} }
@ -457,9 +571,10 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
// Len also fails if the object has a type that len() not accept. // Len also fails if the object has a type that len() not accept.
// //
// a.Len(mySlice, 3) // a.Len(mySlice, 3)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool { func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Len(a.t, object, length, msgAndArgs...) return Len(a.t, object, length, msgAndArgs...)
} }
@ -467,27 +582,30 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface
// Lenf also fails if the object has a type that len() not accept. // Lenf also fails if the object has a type that len() not accept.
// //
// a.Lenf(mySlice, 3, "error message %s", "formatted") // a.Lenf(mySlice, 3, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool { func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Lenf(a.t, object, length, msg, args...) return Lenf(a.t, object, length, msg, args...)
} }
// Nil asserts that the specified object is nil. // Nil asserts that the specified object is nil.
// //
// a.Nil(err) // a.Nil(err)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Nil(a.t, object, msgAndArgs...) return Nil(a.t, object, msgAndArgs...)
} }
// Nilf asserts that the specified object is nil. // Nilf asserts that the specified object is nil.
// //
// a.Nilf(err, "error message %s", "formatted") // a.Nilf(err, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Nilf(a.t, object, msg, args...) return Nilf(a.t, object, msg, args...)
} }
@ -497,9 +615,10 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) b
// if a.NoError(err) { // if a.NoError(err) {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool { func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoError(a.t, err, msgAndArgs...) return NoError(a.t, err, msgAndArgs...)
} }
@ -509,9 +628,10 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
// if a.NoErrorf(err, "error message %s", "formatted") { // if a.NoErrorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool { func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NoErrorf(a.t, err, msg, args...) return NoErrorf(a.t, err, msg, args...)
} }
@ -521,9 +641,10 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) bool {
// a.NotContains("Hello World", "Earth") // a.NotContains("Hello World", "Earth")
// a.NotContains(["Hello", "World"], "Earth") // a.NotContains(["Hello", "World"], "Earth")
// a.NotContains({"Hello": "World"}, "Earth") // a.NotContains({"Hello": "World"}, "Earth")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotContains(a.t, s, contains, msgAndArgs...) return NotContains(a.t, s, contains, msgAndArgs...)
} }
@ -533,9 +654,10 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs
// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") // a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") // a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") // a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotContainsf(a.t, s, contains, msg, args...) return NotContainsf(a.t, s, contains, msg, args...)
} }
@ -545,9 +667,10 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
// if a.NotEmpty(obj) { // if a.NotEmpty(obj) {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEmpty(a.t, object, msgAndArgs...) return NotEmpty(a.t, object, msgAndArgs...)
} }
@ -557,9 +680,10 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) boo
// if a.NotEmptyf(obj, "error message %s", "formatted") { // if a.NotEmptyf(obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEmptyf(a.t, object, msg, args...) return NotEmptyf(a.t, object, msg, args...)
} }
@ -567,11 +691,12 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface
// //
// a.NotEqual(obj1, obj2) // a.NotEqual(obj1, obj2)
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqual(a.t, expected, actual, msgAndArgs...) return NotEqual(a.t, expected, actual, msgAndArgs...)
} }
@ -579,47 +704,52 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
// //
// a.NotEqualf(obj1, obj2, "error message %s", "formatted") // a.NotEqualf(obj1, obj2, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotEqualf(a.t, expected, actual, msg, args...) return NotEqualf(a.t, expected, actual, msg, args...)
} }
// NotNil asserts that the specified object is not nil. // NotNil asserts that the specified object is not nil.
// //
// a.NotNil(err) // a.NotNil(err)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotNil(a.t, object, msgAndArgs...) return NotNil(a.t, object, msgAndArgs...)
} }
// NotNilf asserts that the specified object is not nil. // NotNilf asserts that the specified object is not nil.
// //
// a.NotNilf(err, "error message %s", "formatted") // a.NotNilf(err, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotNilf(a.t, object, msg, args...) return NotNilf(a.t, object, msg, args...)
} }
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// a.NotPanics(func(){ RemainCalm() }) // a.NotPanics(func(){ RemainCalm() })
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool { func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotPanics(a.t, f, msgAndArgs...) return NotPanics(a.t, f, msgAndArgs...)
} }
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") // a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool { func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotPanicsf(a.t, f, msg, args...) return NotPanicsf(a.t, f, msg, args...)
} }
@ -627,9 +757,10 @@ func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...interface{}
// //
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") // a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
// a.NotRegexp("^start", "it's not starting") // a.NotRegexp("^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotRegexp(a.t, rx, str, msgAndArgs...) return NotRegexp(a.t, rx, str, msgAndArgs...)
} }
@ -637,9 +768,10 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
// //
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") // a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") // a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotRegexpf(a.t, rx, str, msg, args...) return NotRegexpf(a.t, rx, str, msg, args...)
} }
@ -647,9 +779,10 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") // a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotSubset(a.t, list, subset, msgAndArgs...) return NotSubset(a.t, list, subset, msgAndArgs...)
} }
@ -657,28 +790,36 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") // a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotSubsetf(a.t, list, subset, msg, args...) return NotSubsetf(a.t, list, subset, msg, args...)
} }
// NotZero asserts that i is not the zero value for its type and returns the truth. // NotZero asserts that i is not the zero value for its type.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotZero(a.t, i, msgAndArgs...) return NotZero(a.t, i, msgAndArgs...)
} }
// NotZerof asserts that i is not the zero value for its type and returns the truth. // NotZerof asserts that i is not the zero value for its type.
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool { func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return NotZerof(a.t, i, msg, args...) return NotZerof(a.t, i, msg, args...)
} }
// Panics asserts that the code inside the specified PanicTestFunc panics. // Panics asserts that the code inside the specified PanicTestFunc panics.
// //
// a.Panics(func(){ GoCrazy() }) // a.Panics(func(){ GoCrazy() })
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool { func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Panics(a.t, f, msgAndArgs...) return Panics(a.t, f, msgAndArgs...)
} }
@ -686,9 +827,10 @@ func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) bool {
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) // a.PanicsWithValue("crazy error", func(){ GoCrazy() })
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return PanicsWithValue(a.t, expected, f, msgAndArgs...) return PanicsWithValue(a.t, expected, f, msgAndArgs...)
} }
@ -696,18 +838,20 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFunc, msgA
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") // a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool { func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return PanicsWithValuef(a.t, expected, f, msg, args...) return PanicsWithValuef(a.t, expected, f, msg, args...)
} }
// Panicsf asserts that the code inside the specified PanicTestFunc panics. // Panicsf asserts that the code inside the specified PanicTestFunc panics.
// //
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") // a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool { func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Panicsf(a.t, f, msg, args...) return Panicsf(a.t, f, msg, args...)
} }
@ -715,9 +859,10 @@ func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interface{}) b
// //
// a.Regexp(regexp.MustCompile("start"), "it's starting") // a.Regexp(regexp.MustCompile("start"), "it's starting")
// a.Regexp("start...$", "it's not starting") // a.Regexp("start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Regexp(a.t, rx, str, msgAndArgs...) return Regexp(a.t, rx, str, msgAndArgs...)
} }
@ -725,9 +870,10 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
// //
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") // a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") // a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Regexpf(a.t, rx, str, msg, args...) return Regexpf(a.t, rx, str, msg, args...)
} }
@ -735,9 +881,10 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") // a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Subset(a.t, list, subset, msgAndArgs...) return Subset(a.t, list, subset, msgAndArgs...)
} }
@ -745,54 +892,65 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") // a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Subsetf(a.t, list, subset, msg, args...) return Subsetf(a.t, list, subset, msg, args...)
} }
// True asserts that the specified value is true. // True asserts that the specified value is true.
// //
// a.True(myBool) // a.True(myBool)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool { func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return True(a.t, value, msgAndArgs...) return True(a.t, value, msgAndArgs...)
} }
// Truef asserts that the specified value is true. // Truef asserts that the specified value is true.
// //
// a.Truef(myBool, "error message %s", "formatted") // a.Truef(myBool, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool { func (a *Assertions) Truef(value bool, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Truef(a.t, value, msg, args...) return Truef(a.t, value, msg, args...)
} }
// WithinDuration asserts that the two times are within duration delta of each other. // WithinDuration asserts that the two times are within duration delta of each other.
// //
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) // a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return WithinDuration(a.t, expected, actual, delta, msgAndArgs...) return WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
} }
// WithinDurationf asserts that the two times are within duration delta of each other. // WithinDurationf asserts that the two times are within duration delta of each other.
// //
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") // a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool { func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return WithinDurationf(a.t, expected, actual, delta, msg, args...) return WithinDurationf(a.t, expected, actual, delta, msg, args...)
} }
// Zero asserts that i is the zero value for its type and returns the truth. // Zero asserts that i is the zero value for its type.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool { func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Zero(a.t, i, msgAndArgs...) return Zero(a.t, i, msgAndArgs...)
} }
// Zerof asserts that i is the zero value for its type and returns the truth. // Zerof asserts that i is the zero value for its type.
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool { func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) bool {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
return Zerof(a.t, i, msg, args...) return Zerof(a.t, i, msg, args...)
} }

View file

@ -1,4 +1,5 @@
{{.CommentWithoutT "a"}} {{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {
if h, ok := a.t.(tHelper); ok { h.Helper() }
return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
} }

View file

@ -27,6 +27,22 @@ type TestingT interface {
Errorf(format string, args ...interface{}) Errorf(format string, args ...interface{})
} }
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
// for table driven tests.
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) bool
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
// for table driven tests.
type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) bool
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
// for table driven tests.
type BoolAssertionFunc func(TestingT, bool, ...interface{}) bool
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
// for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{}) bool
// Comparison a custom function that returns true on success and false on failure // Comparison a custom function that returns true on success and false on failure
type Comparison func() (success bool) type Comparison func() (success bool)
@ -38,21 +54,23 @@ type Comparison func() (success bool)
// //
// This function does no assertion of any kind. // This function does no assertion of any kind.
func ObjectsAreEqual(expected, actual interface{}) bool { func ObjectsAreEqual(expected, actual interface{}) bool {
if expected == nil || actual == nil { if expected == nil || actual == nil {
return expected == actual return expected == actual
} }
if exp, ok := expected.([]byte); ok {
act, ok := actual.([]byte)
if !ok {
return false
} else if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
}
return reflect.DeepEqual(expected, actual)
exp, ok := expected.([]byte)
if !ok {
return reflect.DeepEqual(expected, actual)
}
act, ok := actual.([]byte)
if !ok {
return false
}
if exp == nil || act == nil {
return exp == nil && act == nil
}
return bytes.Equal(exp, act)
} }
// ObjectsAreEqualValues gets whether two objects are equal, or if their // ObjectsAreEqualValues gets whether two objects are equal, or if their
@ -156,27 +174,16 @@ func isTest(name, prefix string) bool {
return !unicode.IsLower(rune) return !unicode.IsLower(rune)
} }
// getWhitespaceString returns a string that is long enough to overwrite the default
// output from the go testing framework.
func getWhitespaceString() string {
_, file, line, ok := runtime.Caller(1)
if !ok {
return ""
}
parts := strings.Split(file, "/")
file = parts[len(parts)-1]
return strings.Repeat(" ", len(fmt.Sprintf("%s:%d: ", file, line)))
}
func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
if len(msgAndArgs) == 0 || msgAndArgs == nil { if len(msgAndArgs) == 0 || msgAndArgs == nil {
return "" return ""
} }
if len(msgAndArgs) == 1 { if len(msgAndArgs) == 1 {
return msgAndArgs[0].(string) msg := msgAndArgs[0]
if msgAsStr, ok := msg.(string); ok {
return msgAsStr
}
return fmt.Sprintf("%+v", msg)
} }
if len(msgAndArgs) > 1 { if len(msgAndArgs) > 1 {
return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...)
@ -195,7 +202,7 @@ func indentMessageLines(message string, longestLabelLen int) string {
// no need to align first line because it starts at the correct location (after the label) // no need to align first line because it starts at the correct location (after the label)
if i != 0 { if i != 0 {
// append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab
outBuf.WriteString("\n\r\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t")
} }
outBuf.WriteString(scanner.Text()) outBuf.WriteString(scanner.Text())
} }
@ -209,6 +216,9 @@ type failNower interface {
// FailNow fails test // FailNow fails test
func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
Fail(t, failureMessage, msgAndArgs...) Fail(t, failureMessage, msgAndArgs...)
// We cannot extend TestingT with FailNow() and // We cannot extend TestingT with FailNow() and
@ -227,8 +237,11 @@ func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool
// Fail reports a failure through // Fail reports a failure through
func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
content := []labeledContent{ content := []labeledContent{
{"Error Trace", strings.Join(CallerInfo(), "\n\r\t\t\t")}, {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")},
{"Error", failureMessage}, {"Error", failureMessage},
} }
@ -244,7 +257,7 @@ func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool {
content = append(content, labeledContent{"Messages", message}) content = append(content, labeledContent{"Messages", message})
} }
t.Errorf("%s", "\r"+getWhitespaceString()+labeledOutput(content...)) t.Errorf("\n%s", ""+labeledOutput(content...))
return false return false
} }
@ -256,7 +269,7 @@ type labeledContent struct {
// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: // labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner:
// //
// \r\t{{label}}:{{align_spaces}}\t{{content}}\n // \t{{label}}:{{align_spaces}}\t{{content}}\n
// //
// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. // The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label.
// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this // If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this
@ -272,7 +285,7 @@ func labeledOutput(content ...labeledContent) string {
} }
var output string var output string
for _, v := range content { for _, v := range content {
output += "\r\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n"
} }
return output return output
} }
@ -281,6 +294,9 @@ func labeledOutput(content ...labeledContent) string {
// //
// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) // assert.Implements(t, (*MyInterface)(nil), new(MyObject))
func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool { func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
interfaceType := reflect.TypeOf(interfaceObject).Elem() interfaceType := reflect.TypeOf(interfaceObject).Elem()
if object == nil { if object == nil {
@ -295,6 +311,9 @@ func Implements(t TestingT, interfaceObject interface{}, object interface{}, msg
// IsType asserts that the specified objects are of the same type. // IsType asserts that the specified objects are of the same type.
func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool { func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) { if !ObjectsAreEqual(reflect.TypeOf(object), reflect.TypeOf(expectedType)) {
return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...) return Fail(t, fmt.Sprintf("Object expected to be of type %v, but was %v", reflect.TypeOf(expectedType), reflect.TypeOf(object)), msgAndArgs...)
@ -307,12 +326,13 @@ func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs
// //
// assert.Equal(t, 123, 123) // assert.Equal(t, 123, 123)
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail. // cannot be determined and will always fail.
func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err := validateEqualArgs(expected, actual); err != nil { if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)", return Fail(t, fmt.Sprintf("Invalid operation: %#v == %#v (%s)",
expected, actual, err), msgAndArgs...) expected, actual, err), msgAndArgs...)
@ -350,9 +370,10 @@ func formatUnequalValues(expected, actual interface{}) (e string, a string) {
// and equal. // and equal.
// //
// assert.EqualValues(t, uint32(123), int32(123)) // assert.EqualValues(t, uint32(123), int32(123))
//
// Returns whether the assertion was successful (true) or not (false).
func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !ObjectsAreEqualValues(expected, actual) { if !ObjectsAreEqualValues(expected, actual) {
diff := diff(expected, actual) diff := diff(expected, actual)
@ -369,15 +390,16 @@ func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs ...interfa
// Exactly asserts that two objects are equal in value and type. // Exactly asserts that two objects are equal in value and type.
// //
// assert.Exactly(t, int32(123), int64(123)) // assert.Exactly(t, int32(123), int64(123))
//
// Returns whether the assertion was successful (true) or not (false).
func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
aType := reflect.TypeOf(expected) aType := reflect.TypeOf(expected)
bType := reflect.TypeOf(actual) bType := reflect.TypeOf(actual)
if aType != bType { if aType != bType {
return Fail(t, fmt.Sprintf("Types expected to match exactly\n\r\t%v != %v", aType, bType), msgAndArgs...) return Fail(t, fmt.Sprintf("Types expected to match exactly\n\t%v != %v", aType, bType), msgAndArgs...)
} }
return Equal(t, expected, actual, msgAndArgs...) return Equal(t, expected, actual, msgAndArgs...)
@ -387,15 +409,27 @@ func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}
// NotNil asserts that the specified object is not nil. // NotNil asserts that the specified object is not nil.
// //
// assert.NotNil(t, err) // assert.NotNil(t, err)
//
// Returns whether the assertion was successful (true) or not (false).
func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !isNil(object) { if !isNil(object) {
return true return true
} }
return Fail(t, "Expected value not to be nil.", msgAndArgs...) return Fail(t, "Expected value not to be nil.", msgAndArgs...)
} }
// containsKind checks if a specified kind in the slice of kinds.
func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool {
for i := 0; i < len(kinds); i++ {
if kind == kinds[i] {
return true
}
}
return false
}
// isNil checks if a specified object is nil or not, without Failing. // isNil checks if a specified object is nil or not, without Failing.
func isNil(object interface{}) bool { func isNil(object interface{}) bool {
if object == nil { if object == nil {
@ -404,7 +438,14 @@ func isNil(object interface{}) bool {
value := reflect.ValueOf(object) value := reflect.ValueOf(object)
kind := value.Kind() kind := value.Kind()
if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { isNilableKind := containsKind(
[]reflect.Kind{
reflect.Chan, reflect.Func,
reflect.Interface, reflect.Map,
reflect.Ptr, reflect.Slice},
kind)
if isNilableKind && value.IsNil() {
return true return true
} }
@ -414,9 +455,10 @@ func isNil(object interface{}) bool {
// Nil asserts that the specified object is nil. // Nil asserts that the specified object is nil.
// //
// assert.Nil(t, err) // assert.Nil(t, err)
//
// Returns whether the assertion was successful (true) or not (false).
func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isNil(object) { if isNil(object) {
return true return true
} }
@ -455,9 +497,10 @@ func isEmpty(object interface{}) bool {
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// assert.Empty(t, obj) // assert.Empty(t, obj)
//
// Returns whether the assertion was successful (true) or not (false).
func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
pass := isEmpty(object) pass := isEmpty(object)
if !pass { if !pass {
@ -474,9 +517,10 @@ func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
// if assert.NotEmpty(t, obj) { // if assert.NotEmpty(t, obj) {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
pass := !isEmpty(object) pass := !isEmpty(object)
if !pass { if !pass {
@ -503,9 +547,10 @@ func getLen(x interface{}) (ok bool, length int) {
// Len also fails if the object has a type that len() not accept. // Len also fails if the object has a type that len() not accept.
// //
// assert.Len(t, mySlice, 3) // assert.Len(t, mySlice, 3)
//
// Returns whether the assertion was successful (true) or not (false).
func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool { func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ok, l := getLen(object) ok, l := getLen(object)
if !ok { if !ok {
return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...) return Fail(t, fmt.Sprintf("\"%s\" could not be applied builtin len()", object), msgAndArgs...)
@ -520,9 +565,15 @@ func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{})
// True asserts that the specified value is true. // True asserts that the specified value is true.
// //
// assert.True(t, myBool) // assert.True(t, myBool)
//
// Returns whether the assertion was successful (true) or not (false).
func True(t TestingT, value bool, msgAndArgs ...interface{}) bool { func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if h, ok := t.(interface {
Helper()
}); ok {
h.Helper()
}
if value != true { if value != true {
return Fail(t, "Should be true", msgAndArgs...) return Fail(t, "Should be true", msgAndArgs...)
@ -535,9 +586,10 @@ func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
// False asserts that the specified value is false. // False asserts that the specified value is false.
// //
// assert.False(t, myBool) // assert.False(t, myBool)
//
// Returns whether the assertion was successful (true) or not (false).
func False(t TestingT, value bool, msgAndArgs ...interface{}) bool { func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if value != false { if value != false {
return Fail(t, "Should be false", msgAndArgs...) return Fail(t, "Should be false", msgAndArgs...)
@ -551,11 +603,12 @@ func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
// //
// assert.NotEqual(t, obj1, obj2) // assert.NotEqual(t, obj1, obj2)
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool { func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err := validateEqualArgs(expected, actual); err != nil { if err := validateEqualArgs(expected, actual); err != nil {
return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)", return Fail(t, fmt.Sprintf("Invalid operation: %#v != %#v (%s)",
expected, actual, err), msgAndArgs...) expected, actual, err), msgAndArgs...)
@ -613,9 +666,10 @@ func includeElement(list interface{}, element interface{}) (ok, found bool) {
// assert.Contains(t, "Hello World", "World") // assert.Contains(t, "Hello World", "World")
// assert.Contains(t, ["Hello", "World"], "World") // assert.Contains(t, ["Hello", "World"], "World")
// assert.Contains(t, {"Hello": "World"}, "Hello") // assert.Contains(t, {"Hello": "World"}, "Hello")
//
// Returns whether the assertion was successful (true) or not (false).
func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ok, found := includeElement(s, contains) ok, found := includeElement(s, contains)
if !ok { if !ok {
@ -635,9 +689,10 @@ func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bo
// assert.NotContains(t, "Hello World", "Earth") // assert.NotContains(t, "Hello World", "Earth")
// assert.NotContains(t, ["Hello", "World"], "Earth") // assert.NotContains(t, ["Hello", "World"], "Earth")
// assert.NotContains(t, {"Hello": "World"}, "Earth") // assert.NotContains(t, {"Hello": "World"}, "Earth")
//
// Returns whether the assertion was successful (true) or not (false).
func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool { func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
ok, found := includeElement(s, contains) ok, found := includeElement(s, contains)
if !ok { if !ok {
@ -655,9 +710,10 @@ func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...interface{})
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") // assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
//
// Returns whether the assertion was successful (true) or not (false).
func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if subset == nil { if subset == nil {
return true // we consider nil to be equal to the nil set return true // we consider nil to be equal to the nil set
} }
@ -698,9 +754,10 @@ func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") // assert.NotSubset(t, [1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
//
// Returns whether the assertion was successful (true) or not (false).
func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) { func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if subset == nil { if subset == nil {
return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...) return Fail(t, fmt.Sprintf("nil is the empty set which is a subset of every set"), msgAndArgs...)
} }
@ -741,10 +798,11 @@ func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...interface{})
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match. // the number of appearances of each of them in both lists should match.
// //
// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])) // assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2])
//
// Returns whether the assertion was successful (true) or not (false).
func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) { func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface{}) (ok bool) {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if isEmpty(listA) && isEmpty(listB) { if isEmpty(listA) && isEmpty(listB) {
return true return true
} }
@ -795,6 +853,9 @@ func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...interface
// Condition uses a Comparison to assert a complex condition. // Condition uses a Comparison to assert a complex condition.
func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool { func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
result := comp() result := comp()
if !result { if !result {
Fail(t, "Condition failed!", msgAndArgs...) Fail(t, "Condition failed!", msgAndArgs...)
@ -831,12 +892,13 @@ func didPanic(f PanicTestFunc) (bool, interface{}) {
// Panics asserts that the code inside the specified PanicTestFunc panics. // Panics asserts that the code inside the specified PanicTestFunc panics.
// //
// assert.Panics(t, func(){ GoCrazy() }) // assert.Panics(t, func(){ GoCrazy() })
//
// Returns whether the assertion was successful (true) or not (false).
func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if funcDidPanic, panicValue := didPanic(f); !funcDidPanic { if funcDidPanic, panicValue := didPanic(f); !funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...) return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
} }
return true return true
@ -846,16 +908,17 @@ func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) // assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() })
//
// Returns whether the assertion was successful (true) or not (false).
func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool { func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
funcDidPanic, panicValue := didPanic(f) funcDidPanic, panicValue := didPanic(f)
if !funcDidPanic { if !funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...) return Fail(t, fmt.Sprintf("func %#v should panic\n\tPanic value:\t%#v", f, panicValue), msgAndArgs...)
} }
if panicValue != expected { if panicValue != expected {
return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%v\n\r\tPanic value:\t%v", f, expected, panicValue), msgAndArgs...) return Fail(t, fmt.Sprintf("func %#v should panic with value:\t%#v\n\tPanic value:\t%#v", f, expected, panicValue), msgAndArgs...)
} }
return true return true
@ -864,12 +927,13 @@ func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, msgAndAr
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// assert.NotPanics(t, func(){ RemainCalm() }) // assert.NotPanics(t, func(){ RemainCalm() })
//
// Returns whether the assertion was successful (true) or not (false).
func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool { func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if funcDidPanic, panicValue := didPanic(f); funcDidPanic { if funcDidPanic, panicValue := didPanic(f); funcDidPanic {
return Fail(t, fmt.Sprintf("func %#v should not panic\n\r\tPanic value:\t%v", f, panicValue), msgAndArgs...) return Fail(t, fmt.Sprintf("func %#v should not panic\n\tPanic value:\t%v", f, panicValue), msgAndArgs...)
} }
return true return true
@ -878,9 +942,10 @@ func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
// WithinDuration asserts that the two times are within duration delta of each other. // WithinDuration asserts that the two times are within duration delta of each other.
// //
// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) // assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second)
//
// Returns whether the assertion was successful (true) or not (false).
func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool { func WithinDuration(t TestingT, expected, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
dt := expected.Sub(actual) dt := expected.Sub(actual)
if dt < -delta || dt > delta { if dt < -delta || dt > delta {
@ -929,9 +994,10 @@ func toFloat(x interface{}) (float64, bool) {
// InDelta asserts that the two numerals are within delta of each other. // InDelta asserts that the two numerals are within delta of each other.
// //
// assert.InDelta(t, math.Pi, (22 / 7.0), 0.01) // assert.InDelta(t, math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
af, aok := toFloat(expected) af, aok := toFloat(expected)
bf, bok := toFloat(actual) bf, bok := toFloat(actual)
@ -958,6 +1024,9 @@ func InDelta(t TestingT, expected, actual interface{}, delta float64, msgAndArgs
// InDeltaSlice is the same as InDelta, except it compares two slices. // InDeltaSlice is the same as InDelta, except it compares two slices.
func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if expected == nil || actual == nil || if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice { reflect.TypeOf(expected).Kind() != reflect.Slice {
@ -979,6 +1048,9 @@ func InDeltaSlice(t TestingT, expected, actual interface{}, delta float64, msgAn
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool { func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if expected == nil || actual == nil || if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Map || reflect.TypeOf(actual).Kind() != reflect.Map ||
reflect.TypeOf(expected).Kind() != reflect.Map { reflect.TypeOf(expected).Kind() != reflect.Map {
@ -989,7 +1061,7 @@ func InDeltaMapValues(t TestingT, expected, actual interface{}, delta float64, m
actualMap := reflect.ValueOf(actual) actualMap := reflect.ValueOf(actual)
if expectedMap.Len() != actualMap.Len() { if expectedMap.Len() != actualMap.Len() {
return Fail(t, "Arguments must have the same numbe of keys", msgAndArgs...) return Fail(t, "Arguments must have the same number of keys", msgAndArgs...)
} }
for _, k := range expectedMap.MapKeys() { for _, k := range expectedMap.MapKeys() {
@ -1035,9 +1107,10 @@ func calcRelativeError(expected, actual interface{}) (float64, error) {
} }
// InEpsilon asserts that expected and actual have a relative error less than epsilon // InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
actualEpsilon, err := calcRelativeError(expected, actual) actualEpsilon, err := calcRelativeError(expected, actual)
if err != nil { if err != nil {
return Fail(t, err.Error(), msgAndArgs...) return Fail(t, err.Error(), msgAndArgs...)
@ -1052,6 +1125,9 @@ func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64, msgAnd
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool { func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if expected == nil || actual == nil || if expected == nil || actual == nil ||
reflect.TypeOf(actual).Kind() != reflect.Slice || reflect.TypeOf(actual).Kind() != reflect.Slice ||
reflect.TypeOf(expected).Kind() != reflect.Slice { reflect.TypeOf(expected).Kind() != reflect.Slice {
@ -1081,9 +1157,10 @@ func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon float64, m
// if assert.NoError(t, err) { // if assert.NoError(t, err) {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err != nil { if err != nil {
return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...)
} }
@ -1097,9 +1174,10 @@ func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
// if assert.Error(t, err) { // if assert.Error(t, err) {
// assert.Equal(t, expectedError, err) // assert.Equal(t, expectedError, err)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func Error(t TestingT, err error, msgAndArgs ...interface{}) bool { func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if err == nil { if err == nil {
return Fail(t, "An error is expected but got nil.", msgAndArgs...) return Fail(t, "An error is expected but got nil.", msgAndArgs...)
@ -1113,9 +1191,10 @@ func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// assert.EqualError(t, err, expectedErrorString) // assert.EqualError(t, err, expectedErrorString)
//
// Returns whether the assertion was successful (true) or not (false).
func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool { func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if !Error(t, theError, msgAndArgs...) { if !Error(t, theError, msgAndArgs...) {
return false return false
} }
@ -1148,9 +1227,10 @@ func matchRegexp(rx interface{}, str interface{}) bool {
// //
// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") // assert.Regexp(t, regexp.MustCompile("start"), "it's starting")
// assert.Regexp(t, "start...$", "it's not starting") // assert.Regexp(t, "start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
match := matchRegexp(rx, str) match := matchRegexp(rx, str)
@ -1165,9 +1245,10 @@ func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface
// //
// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") // assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting")
// assert.NotRegexp(t, "^start", "it's not starting") // assert.NotRegexp(t, "^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool { func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
match := matchRegexp(rx, str) match := matchRegexp(rx, str)
if match { if match {
@ -1178,16 +1259,22 @@ func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interf
} }
// Zero asserts that i is the zero value for its type and returns the truth. // Zero asserts that i is the zero value for its type.
func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { if i != nil && !reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...) return Fail(t, fmt.Sprintf("Should be zero, but was %v", i), msgAndArgs...)
} }
return true return true
} }
// NotZero asserts that i is not the zero value for its type and returns the truth. // NotZero asserts that i is not the zero value for its type.
func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool { func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) { if i == nil || reflect.DeepEqual(i, reflect.Zero(reflect.TypeOf(i)).Interface()) {
return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...) return Fail(t, fmt.Sprintf("Should not be zero, but was %v", i), msgAndArgs...)
} }
@ -1196,6 +1283,9 @@ func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. // FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool { func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
info, err := os.Lstat(path) info, err := os.Lstat(path)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -1211,6 +1301,9 @@ func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. // DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool { func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
info, err := os.Lstat(path) info, err := os.Lstat(path)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
@ -1227,9 +1320,10 @@ func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
// JSONEq asserts that two JSON strings are equivalent. // JSONEq asserts that two JSON strings are equivalent.
// //
// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) // assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool { func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
var expectedJSONAsInterface, actualJSONAsInterface interface{} var expectedJSONAsInterface, actualJSONAsInterface interface{}
if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil { if err := json.Unmarshal([]byte(expected), &expectedJSONAsInterface); err != nil {
@ -1255,7 +1349,7 @@ func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
} }
// diff returns a diff of both values as long as both are of the same type and // diff returns a diff of both values as long as both are of the same type and
// are a struct, map, slice or array. Otherwise it returns an empty string. // are a struct, map, slice, array or string. Otherwise it returns an empty string.
func diff(expected interface{}, actual interface{}) string { func diff(expected interface{}, actual interface{}) string {
if expected == nil || actual == nil { if expected == nil || actual == nil {
return "" return ""
@ -1268,12 +1362,18 @@ func diff(expected interface{}, actual interface{}) string {
return "" return ""
} }
if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array { if ek != reflect.Struct && ek != reflect.Map && ek != reflect.Slice && ek != reflect.Array && ek != reflect.String {
return "" return ""
} }
e := spewConfig.Sdump(expected) var e, a string
a := spewConfig.Sdump(actual) if et != reflect.TypeOf("") {
e = spewConfig.Sdump(expected)
a = spewConfig.Sdump(actual)
} else {
e = expected.(string)
a = actual.(string)
}
diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{ diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
A: difflib.SplitLines(e), A: difflib.SplitLines(e),
@ -1310,3 +1410,7 @@ var spewConfig = spew.ConfigState{
DisableCapacities: true, DisableCapacities: true,
SortKeys: true, SortKeys: true,
} }
type tHelper interface {
Helper()
}

View file

@ -2,6 +2,7 @@ package assert
import ( import (
"bytes" "bytes"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -174,6 +175,8 @@ func TestIsType(t *testing.T) {
} }
type myType string
func TestEqual(t *testing.T) { func TestEqual(t *testing.T) {
mockT := new(testing.T) mockT := new(testing.T)
@ -199,6 +202,9 @@ func TestEqual(t *testing.T) {
if !Equal(mockT, uint64(123), uint64(123)) { if !Equal(mockT, uint64(123), uint64(123)) {
t.Error("Equal should return true") t.Error("Equal should return true")
} }
if !Equal(mockT, myType("1"), myType("1")) {
t.Error("Equal should return true")
}
if !Equal(mockT, &struct{}{}, &struct{}{}) { if !Equal(mockT, &struct{}{}, &struct{}{}) {
t.Error("Equal should return true (pointer equality is based on equality of underlying value)") t.Error("Equal should return true (pointer equality is based on equality of underlying value)")
} }
@ -206,6 +212,9 @@ func TestEqual(t *testing.T) {
if Equal(mockT, m["bar"], "something") { if Equal(mockT, m["bar"], "something") {
t.Error("Equal should return false") t.Error("Equal should return false")
} }
if Equal(mockT, myType("1"), myType("2")) {
t.Error("Equal should return false")
}
} }
// bufferT implements TestingT. Its implementation of Errorf writes the output that would be produced by // bufferT implements TestingT. Its implementation of Errorf writes the output that would be produced by
@ -250,6 +259,21 @@ func (t *bufferT) Errorf(format string, args ...interface{}) {
t.buf.WriteString(decorate(fmt.Sprintf(format, args...))) t.buf.WriteString(decorate(fmt.Sprintf(format, args...)))
} }
func TestStringEqual(t *testing.T) {
for i, currCase := range []struct {
equalWant string
equalGot string
msgAndArgs []interface{}
want string
}{
{equalWant: "hi, \nmy name is", equalGot: "what,\nmy name is", want: "\tassertions.go:\\d+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"hi, \\\\nmy name is\"\n\\s+actual\\s+: \"what,\\\\nmy name is\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1,2 \\+1,2 @@\n\\s+-hi, \n\\s+\\+what,\n\\s+my name is"},
} {
mockT := &bufferT{}
Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...)
Regexp(t, regexp.MustCompile(currCase.want), mockT.buf.String(), "Case %d", i)
}
}
func TestEqualFormatting(t *testing.T) { func TestEqualFormatting(t *testing.T) {
for i, currCase := range []struct { for i, currCase := range []struct {
equalWant string equalWant string
@ -257,8 +281,10 @@ func TestEqualFormatting(t *testing.T) {
msgAndArgs []interface{} msgAndArgs []interface{}
want string want string
}{ }{
{equalWant: "want", equalGot: "got", want: "\tassertions.go:[0-9]+: \r \r\tError Trace:\t\n\t\t\r\tError: \tNot equal: \n\t\t\r\t \texpected: \"want\"\n\t\t\r\t \tactual : \"got\"\n"}, {equalWant: "want", equalGot: "got", want: "\tassertions.go:\\d+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n"},
{equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{"hello, %v!", "world"}, want: "\tassertions.go:[0-9]+: \r \r\tError Trace:\t\n\t\t\r\tError: \tNot equal: \n\t\t\r\t \texpected: \"want\"\n\t\t\r\t \tactual : \"got\"\n\t\t\r\tMessages: \thello, world!\n"}, {equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{"hello, %v!", "world"}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+hello, world!\n"},
{equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{123}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+123\n"},
{equalWant: "want", equalGot: "got", msgAndArgs: []interface{}{struct{ a string }{"hello"}}, want: "\tassertions.go:[0-9]+: \n\t+Error Trace:\t\n\t+Error:\\s+Not equal:\\s+\n\\s+expected: \"want\"\n\\s+actual\\s+: \"got\"\n\\s+Diff:\n\\s+-+ Expected\n\\s+\\++ Actual\n\\s+@@ -1 \\+1 @@\n\\s+-want\n\\s+\\+got\n\\s+Messages:\\s+{a:hello}\n"},
} { } {
mockT := &bufferT{} mockT := &bufferT{}
Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...) Equal(mockT, currCase.equalWant, currCase.equalGot, currCase.msgAndArgs...)
@ -1579,3 +1605,199 @@ func TestEqualArgsValidation(t *testing.T) {
err := validateEqualArgs(time.Now, time.Now) err := validateEqualArgs(time.Now, time.Now)
EqualError(t, err, "cannot take func type as argument") EqualError(t, err, "cannot take func type as argument")
} }
func ExampleComparisonAssertionFunc() {
t := &testing.T{} // provided by test
adder := func(x, y int) int {
return x + y
}
type args struct {
x int
y int
}
tests := []struct {
name string
args args
expect int
assertion ComparisonAssertionFunc
}{
{"2+2=4", args{2, 2}, 4, Equal},
{"2+2!=5", args{2, 2}, 5, NotEqual},
{"2+3==5", args{2, 3}, 5, Exactly},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y))
})
}
}
func TestComparisonAssertionFunc(t *testing.T) {
type iface interface {
Name() string
}
tests := []struct {
name string
expect interface{}
got interface{}
assertion ComparisonAssertionFunc
}{
{"implements", (*iface)(nil), t, Implements},
{"isType", (*testing.T)(nil), t, IsType},
{"equal", t, t, Equal},
{"equalValues", t, t, EqualValues},
{"exactly", t, t, Exactly},
{"notEqual", t, nil, NotEqual},
{"notContains", []int{1, 2, 3}, 4, NotContains},
{"subset", []int{1, 2, 3, 4}, []int{2, 3}, Subset},
{"notSubset", []int{1, 2, 3, 4}, []int{0, 3}, NotSubset},
{"elementsMatch", []byte("abc"), []byte("bac"), ElementsMatch},
{"regexp", "^t.*y$", "testify", Regexp},
{"notRegexp", "^t.*y$", "Testify", NotRegexp},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, tt.got)
})
}
}
func ExampleValueAssertionFunc() {
t := &testing.T{} // provided by test
dumbParse := func(input string) interface{} {
var x interface{}
json.Unmarshal([]byte(input), &x)
return x
}
tests := []struct {
name string
arg string
assertion ValueAssertionFunc
}{
{"true is not nil", "true", NotNil},
{"empty string is nil", "", Nil},
{"zero is not nil", "0", NotNil},
{"zero is zero", "0", Zero},
{"false is zero", "false", Zero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, dumbParse(tt.arg))
})
}
}
func TestValueAssertionFunc(t *testing.T) {
tests := []struct {
name string
value interface{}
assertion ValueAssertionFunc
}{
{"notNil", true, NotNil},
{"nil", nil, Nil},
{"empty", []int{}, Empty},
{"notEmpty", []int{1}, NotEmpty},
{"zero", false, Zero},
{"notZero", 42, NotZero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleBoolAssertionFunc() {
t := &testing.T{} // provided by test
isOkay := func(x int) bool {
return x >= 42
}
tests := []struct {
name string
arg int
assertion BoolAssertionFunc
}{
{"-1 is bad", -1, False},
{"42 is good", 42, True},
{"41 is bad", 41, False},
{"45 is cool", 45, True},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, isOkay(tt.arg))
})
}
}
func TestBoolAssertionFunc(t *testing.T) {
tests := []struct {
name string
value bool
assertion BoolAssertionFunc
}{
{"true", true, True},
{"false", false, False},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleErrorAssertionFunc() {
t := &testing.T{} // provided by test
dumbParseNum := func(input string, v interface{}) error {
return json.Unmarshal([]byte(input), v)
}
tests := []struct {
name string
arg string
assertion ErrorAssertionFunc
}{
{"1.2 is number", "1.2", NoError},
{"1.2.3 not number", "1.2.3", Error},
{"true is not number", "true", Error},
{"3 is number", "3", NoError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var x float64
tt.assertion(t, dumbParseNum(tt.arg, &x))
})
}
}
func TestErrorAssertionFunc(t *testing.T) {
tests := []struct {
name string
err error
assertion ErrorAssertionFunc
}{
{"noError", nil, NoError},
{"error", errors.New("whoops"), Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.err)
})
}
}

View file

@ -12,10 +12,11 @@ import (
// an error if building a new request fails. // an error if building a new request fails.
func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) {
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, err := http.NewRequest(method, url+"?"+values.Encode(), nil) req, err := http.NewRequest(method, url, nil)
if err != nil { if err != nil {
return -1, err return -1, err
} }
req.URL.RawQuery = values.Encode()
handler(w, req) handler(w, req)
return w.Code, nil return w.Code, nil
} }
@ -26,6 +27,9 @@ func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values) code, err := httpCode(handler, method, url, values)
if err != nil { if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
@ -46,6 +50,9 @@ func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, value
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values) code, err := httpCode(handler, method, url, values)
if err != nil { if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
@ -66,6 +73,9 @@ func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, valu
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
code, err := httpCode(handler, method, url, values) code, err := httpCode(handler, method, url, values)
if err != nil { if err != nil {
Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err)) Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err))
@ -95,10 +105,13 @@ func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) s
// HTTPBodyContains asserts that a specified handler returns a // HTTPBodyContains asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// assert.HTTPBodyContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
body := HTTPBody(handler, method, url, values) body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))
@ -112,10 +125,13 @@ func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string,
// HTTPBodyNotContains asserts that a specified handler returns a // HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// assert.HTTPBodyNotContains(t, myHandler, "www.google.com", nil, "I'm Feeling Lucky") // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
body := HTTPBody(handler, method, url, values) body := HTTPBody(handler, method, url, values)
contains := strings.Contains(body, fmt.Sprint(str)) contains := strings.Contains(body, fmt.Sprint(str))

View file

@ -89,6 +89,35 @@ func httpHelloName(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf("Hello, %s!", name))) w.Write([]byte(fmt.Sprintf("Hello, %s!", name)))
} }
func TestHTTPRequestWithNoParams(t *testing.T) {
var got *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
got = r
w.WriteHeader(http.StatusOK)
}
True(t, HTTPSuccess(t, handler, "GET", "/url", nil))
Empty(t, got.URL.Query())
Equal(t, "/url", got.URL.RequestURI())
}
func TestHTTPRequestWithParams(t *testing.T) {
var got *http.Request
handler := func(w http.ResponseWriter, r *http.Request) {
got = r
w.WriteHeader(http.StatusOK)
}
params := url.Values{}
params.Add("id", "12345")
True(t, HTTPSuccess(t, handler, "GET", "/url", params))
Equal(t, url.Values{"id": []string{"12345"}}, got.URL.Query())
Equal(t, "/url?id=12345", got.URL.String())
Equal(t, "/url?id=12345", got.URL.RequestURI())
}
func TestHttpBody(t *testing.T) { func TestHttpBody(t *testing.T) {
assert := New(t) assert := New(t)
mockT := new(testing.T) mockT := new(testing.T)

7
vendor/github.com/stretchr/testify/go.mod generated vendored Normal file
View file

@ -0,0 +1,7 @@
module github.com/stretchr/testify
require (
github.com/davecgh/go-spew v1.1.0
github.com/pmezard/go-difflib v1.0.0
github.com/stretchr/objx v0.1.0
)

6
vendor/github.com/stretchr/testify/go.sum generated vendored Normal file
View file

@ -0,0 +1,6 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=

View file

@ -42,6 +42,9 @@ type Call struct {
// this method is called. // this method is called.
ReturnArguments Arguments ReturnArguments Arguments
// Holds the caller info for the On() call
callerInfo []string
// The number of times to return the return arguments when setting // The number of times to return the return arguments when setting
// expectations. 0 means to always return the value. // expectations. 0 means to always return the value.
Repeatability int Repeatability int
@ -64,12 +67,13 @@ type Call struct {
RunFn func(Arguments) RunFn func(Arguments)
} }
func newCall(parent *Mock, methodName string, methodArguments ...interface{}) *Call { func newCall(parent *Mock, methodName string, callerInfo []string, methodArguments ...interface{}) *Call {
return &Call{ return &Call{
Parent: parent, Parent: parent,
Method: methodName, Method: methodName,
Arguments: methodArguments, Arguments: methodArguments,
ReturnArguments: make([]interface{}, 0), ReturnArguments: make([]interface{}, 0),
callerInfo: callerInfo,
Repeatability: 0, Repeatability: 0,
WaitFor: nil, WaitFor: nil,
RunFn: nil, RunFn: nil,
@ -172,6 +176,7 @@ func (c *Call) Maybe() *Call {
// Mock. // Mock.
// On("MyMethod", 1).Return(nil). // On("MyMethod", 1).Return(nil).
// On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error")) // On("MyOtherMethod", 'a', 'b', 'c').Return(errors.New("Some Error"))
//go:noinline
func (c *Call) On(methodName string, arguments ...interface{}) *Call { func (c *Call) On(methodName string, arguments ...interface{}) *Call {
return c.Parent.On(methodName, arguments...) return c.Parent.On(methodName, arguments...)
} }
@ -187,6 +192,10 @@ type Mock struct {
// Holds the calls that were made to this mocked object. // Holds the calls that were made to this mocked object.
Calls []Call Calls []Call
// test is An optional variable that holds the test struct, to be used when an
// invalid mock call was made.
test TestingT
// TestData holds any data that might be useful for testing. Testify ignores // TestData holds any data that might be useful for testing. Testify ignores
// this data completely allowing you to do whatever you like with it. // this data completely allowing you to do whatever you like with it.
testData objx.Map testData objx.Map
@ -209,6 +218,27 @@ func (m *Mock) TestData() objx.Map {
Setting expectations Setting expectations
*/ */
// Test sets the test struct variable of the mock object
func (m *Mock) Test(t TestingT) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.test = t
}
// fail fails the current test with the given formatted format and args.
// In case that a test was defined, it uses the test APIs for failing a test,
// otherwise it uses panic.
func (m *Mock) fail(format string, args ...interface{}) {
m.mutex.Lock()
defer m.mutex.Unlock()
if m.test == nil {
panic(fmt.Sprintf(format, args...))
}
m.test.Errorf(format, args...)
m.test.FailNow()
}
// On starts a description of an expectation of the specified method // On starts a description of an expectation of the specified method
// being called. // being called.
// //
@ -222,7 +252,7 @@ func (m *Mock) On(methodName string, arguments ...interface{}) *Call {
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
c := newCall(m, methodName, arguments...) c := newCall(m, methodName, assert.CallerInfo(), arguments...)
m.ExpectedCalls = append(m.ExpectedCalls, c) m.ExpectedCalls = append(m.ExpectedCalls, c)
return c return c
} }
@ -245,27 +275,25 @@ func (m *Mock) findExpectedCall(method string, arguments ...interface{}) (int, *
return -1, nil return -1, nil
} }
func (m *Mock) findClosestCall(method string, arguments ...interface{}) (bool, *Call) { func (m *Mock) findClosestCall(method string, arguments ...interface{}) (*Call, string) {
diffCount := 0 var diffCount int
var closestCall *Call var closestCall *Call
var err string
for _, call := range m.expectedCalls() { for _, call := range m.expectedCalls() {
if call.Method == method { if call.Method == method {
_, tempDiffCount := call.Arguments.Diff(arguments) errInfo, tempDiffCount := call.Arguments.Diff(arguments)
if tempDiffCount < diffCount || diffCount == 0 { if tempDiffCount < diffCount || diffCount == 0 {
diffCount = tempDiffCount diffCount = tempDiffCount
closestCall = call closestCall = call
err = errInfo
} }
} }
} }
if closestCall == nil { return closestCall, err
return false, nil
}
return true, closestCall
} }
func callString(method string, arguments Arguments, includeArgumentValues bool) string { func callString(method string, arguments Arguments, includeArgumentValues bool) string {
@ -312,6 +340,7 @@ func (m *Mock) Called(arguments ...interface{}) Arguments {
// If Call.WaitFor is set, blocks until the channel is closed or receives a message. // If Call.WaitFor is set, blocks until the channel is closed or receives a message.
func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments { func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Arguments {
m.mutex.Lock() m.mutex.Lock()
//TODO: could combine expected and closes in single loop
found, call := m.findExpectedCall(methodName, arguments...) found, call := m.findExpectedCall(methodName, arguments...)
if found < 0 { if found < 0 {
@ -322,13 +351,18 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
// b) the arguments are not what was expected, or // b) the arguments are not what was expected, or
// c) the developer has forgotten to add an accompanying On...Return pair. // c) the developer has forgotten to add an accompanying On...Return pair.
closestFound, closestCall := m.findClosestCall(methodName, arguments...) closestCall, mismatch := m.findClosestCall(methodName, arguments...)
m.mutex.Unlock() m.mutex.Unlock()
if closestFound { if closestCall != nil {
panic(fmt.Sprintf("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\n", callString(methodName, arguments, true), callString(methodName, closestCall.Arguments, true), diffArguments(closestCall.Arguments, arguments))) m.fail("\n\nmock: Unexpected Method Call\n-----------------------------\n\n%s\n\nThe closest call I have is: \n\n%s\n\n%s\nDiff: %s",
callString(methodName, arguments, true),
callString(methodName, closestCall.Arguments, true),
diffArguments(closestCall.Arguments, arguments),
strings.TrimSpace(mismatch),
)
} else { } else {
panic(fmt.Sprintf("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo())) m.fail("\nassert: mock: I don't know what to return because the method call was unexpected.\n\tEither do Mock.On(\"%s\").Return(...) first, or remove the %s() call.\n\tThis method was unexpected:\n\t\t%s\n\tat: %s", methodName, methodName, callString(methodName, arguments, true), assert.CallerInfo())
} }
} }
@ -340,7 +374,7 @@ func (m *Mock) MethodCalled(methodName string, arguments ...interface{}) Argumen
call.totalCalls++ call.totalCalls++
// add the call // add the call
m.Calls = append(m.Calls, *newCall(m, methodName, arguments...)) m.Calls = append(m.Calls, *newCall(m, methodName, assert.CallerInfo(), arguments...))
m.mutex.Unlock() m.mutex.Unlock()
// block if specified // block if specified
@ -378,6 +412,9 @@ type assertExpectationser interface {
// //
// Calls may have occurred in any order. // Calls may have occurred in any order.
func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool { func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
for _, obj := range testObjects { for _, obj := range testObjects {
if m, ok := obj.(Mock); ok { if m, ok := obj.(Mock); ok {
t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)") t.Logf("Deprecated mock.AssertExpectationsForObjects(myMock.Mock) use mock.AssertExpectationsForObjects(myMock)")
@ -385,6 +422,7 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
} }
m := obj.(assertExpectationser) m := obj.(assertExpectationser)
if !m.AssertExpectations(t) { if !m.AssertExpectations(t) {
t.Logf("Expectations didn't match for Mock: %+v", reflect.TypeOf(m))
return false return false
} }
} }
@ -394,6 +432,9 @@ func AssertExpectationsForObjects(t TestingT, testObjects ...interface{}) bool {
// AssertExpectations asserts that everything specified with On and Return was // AssertExpectations asserts that everything specified with On and Return was
// in fact called as expected. Calls may have occurred in any order. // in fact called as expected. Calls may have occurred in any order.
func (m *Mock) AssertExpectations(t TestingT) bool { func (m *Mock) AssertExpectations(t TestingT) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
var somethingMissing bool var somethingMissing bool
@ -405,13 +446,14 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 { if !expectedCall.optional && !m.methodWasCalled(expectedCall.Method, expectedCall.Arguments) && expectedCall.totalCalls == 0 {
somethingMissing = true somethingMissing = true
failedExpectations++ failedExpectations++
t.Logf("\u274C\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo)
} else { } else {
if expectedCall.Repeatability > 0 { if expectedCall.Repeatability > 0 {
somethingMissing = true somethingMissing = true
failedExpectations++ failedExpectations++
t.Logf("FAIL:\t%s(%s)\n\t\tat: %s", expectedCall.Method, expectedCall.Arguments.String(), expectedCall.callerInfo)
} else { } else {
t.Logf("\u2705\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String()) t.Logf("PASS:\t%s(%s)", expectedCall.Method, expectedCall.Arguments.String())
} }
} }
} }
@ -425,6 +467,9 @@ func (m *Mock) AssertExpectations(t TestingT) bool {
// AssertNumberOfCalls asserts that the method was called expectedCalls times. // AssertNumberOfCalls asserts that the method was called expectedCalls times.
func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool { func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls int) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
var actualCalls int var actualCalls int
@ -439,11 +484,22 @@ func (m *Mock) AssertNumberOfCalls(t TestingT, methodName string, expectedCalls
// AssertCalled asserts that the method was called. // AssertCalled asserts that the method was called.
// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. // It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool { func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
if !assert.True(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method should have been called with %d argument(s), but was not.", methodName, len(arguments))) { if !m.methodWasCalled(methodName, arguments) {
t.Logf("%v", m.expectedCalls()) var calledWithArgs []string
return false for _, call := range m.calls() {
calledWithArgs = append(calledWithArgs, fmt.Sprintf("%v", call.Arguments))
}
if len(calledWithArgs) == 0 {
return assert.Fail(t, "Should have called with given arguments",
fmt.Sprintf("Expected %q to have been called with:\n%v\nbut no actual calls happened", methodName, arguments))
}
return assert.Fail(t, "Should have called with given arguments",
fmt.Sprintf("Expected %q to have been called with:\n%v\nbut actual calls were:\n %v", methodName, arguments, strings.Join(calledWithArgs, "\n")))
} }
return true return true
} }
@ -451,11 +507,14 @@ func (m *Mock) AssertCalled(t TestingT, methodName string, arguments ...interfac
// AssertNotCalled asserts that the method was not called. // AssertNotCalled asserts that the method was not called.
// It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method. // It can produce a false result when an argument is a pointer type and the underlying value changed after calling the mocked method.
func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool { func (m *Mock) AssertNotCalled(t TestingT, methodName string, arguments ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
m.mutex.Lock() m.mutex.Lock()
defer m.mutex.Unlock() defer m.mutex.Unlock()
if !assert.False(t, m.methodWasCalled(methodName, arguments), fmt.Sprintf("The \"%s\" method was called with %d argument(s), but should NOT have been.", methodName, len(arguments))) { if m.methodWasCalled(methodName, arguments) {
t.Logf("%v", m.expectedCalls()) return assert.Fail(t, "Should not have called with given arguments",
return false fmt.Sprintf("Expected %q to not have been called with:\n%v\nbut actually it was.", methodName, arguments))
} }
return true return true
} }
@ -495,7 +554,7 @@ type Arguments []interface{}
const ( const (
// Anything is used in Diff and Assert when the argument being tested // Anything is used in Diff and Assert when the argument being tested
// shouldn't be taken into consideration. // shouldn't be taken into consideration.
Anything string = "mock.Anything" Anything = "mock.Anything"
) )
// AnythingOfTypeArgument is a string that contains the type of an argument // AnythingOfTypeArgument is a string that contains the type of an argument
@ -598,6 +657,7 @@ func (args Arguments) Is(objects ...interface{}) bool {
// //
// Returns the diff string and number of differences found. // Returns the diff string and number of differences found.
func (args Arguments) Diff(objects []interface{}) (string, int) { func (args Arguments) Diff(objects []interface{}) (string, int) {
//TODO: could return string as error and nil for No difference
var output = "\n" var output = "\n"
var differences int var differences int
@ -609,25 +669,30 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
for i := 0; i < maxArgCount; i++ { for i := 0; i < maxArgCount; i++ {
var actual, expected interface{} var actual, expected interface{}
var actualFmt, expectedFmt string
if len(objects) <= i { if len(objects) <= i {
actual = "(Missing)" actual = "(Missing)"
actualFmt = "(Missing)"
} else { } else {
actual = objects[i] actual = objects[i]
actualFmt = fmt.Sprintf("(%[1]T=%[1]v)", actual)
} }
if len(args) <= i { if len(args) <= i {
expected = "(Missing)" expected = "(Missing)"
expectedFmt = "(Missing)"
} else { } else {
expected = args[i] expected = args[i]
expectedFmt = fmt.Sprintf("(%[1]T=%[1]v)", expected)
} }
if matcher, ok := expected.(argumentMatcher); ok { if matcher, ok := expected.(argumentMatcher); ok {
if matcher.Matches(actual) { if matcher.Matches(actual) {
output = fmt.Sprintf("%s\t%d: \u2705 %s matched by %s\n", output, i, actual, matcher) output = fmt.Sprintf("%s\t%d: PASS: %s matched by %s\n", output, i, actualFmt, matcher)
} else { } else {
differences++ differences++
output = fmt.Sprintf("%s\t%d: \u2705 %s not matched by %s\n", output, i, actual, matcher) output = fmt.Sprintf("%s\t%d: FAIL: %s not matched by %s\n", output, i, actualFmt, matcher)
} }
} else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() { } else if reflect.TypeOf(expected) == reflect.TypeOf((*AnythingOfTypeArgument)(nil)).Elem() {
@ -635,7 +700,7 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) { if reflect.TypeOf(actual).Name() != string(expected.(AnythingOfTypeArgument)) && reflect.TypeOf(actual).String() != string(expected.(AnythingOfTypeArgument)) {
// not match // not match
differences++ differences++
output = fmt.Sprintf("%s\t%d: \u274C type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actual) output = fmt.Sprintf("%s\t%d: FAIL: type %s != type %s - %s\n", output, i, expected, reflect.TypeOf(actual).Name(), actualFmt)
} }
} else { } else {
@ -644,11 +709,11 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) { if assert.ObjectsAreEqual(expected, Anything) || assert.ObjectsAreEqual(actual, Anything) || assert.ObjectsAreEqual(actual, expected) {
// match // match
output = fmt.Sprintf("%s\t%d: \u2705 %s == %s\n", output, i, actual, expected) output = fmt.Sprintf("%s\t%d: PASS: %s == %s\n", output, i, actualFmt, expectedFmt)
} else { } else {
// not match // not match
differences++ differences++
output = fmt.Sprintf("%s\t%d: \u274C %s != %s\n", output, i, actual, expected) output = fmt.Sprintf("%s\t%d: FAIL: %s != %s\n", output, i, actualFmt, expectedFmt)
} }
} }
@ -665,6 +730,9 @@ func (args Arguments) Diff(objects []interface{}) (string, int) {
// Assert compares the arguments with the specified objects and fails if // Assert compares the arguments with the specified objects and fails if
// they do not exactly match. // they do not exactly match.
func (args Arguments) Assert(t TestingT, objects ...interface{}) bool { func (args Arguments) Assert(t TestingT, objects ...interface{}) bool {
if h, ok := t.(tHelper); ok {
h.Helper()
}
// get the differences // get the differences
diff, diffCount := args.Diff(objects) diff, diffCount := args.Diff(objects)
@ -812,3 +880,7 @@ var spewConfig = spew.ConfigState{
DisableCapacities: true, DisableCapacities: true,
SortKeys: true, SortKeys: true,
} }
type tHelper interface {
Helper()
}

View file

@ -3,6 +3,8 @@ package mock
import ( import (
"errors" "errors"
"fmt" "fmt"
"regexp"
"runtime"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -30,6 +32,7 @@ func (i *TestExampleImplementation) TheExampleMethod(a, b, c int) (int, error) {
return args.Int(0), errors.New("Whoops") return args.Int(0), errors.New("Whoops")
} }
//go:noinline
func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) { func (i *TestExampleImplementation) TheExampleMethod2(yesorno bool) {
i.Called(yesorno) i.Called(yesorno)
} }
@ -90,6 +93,34 @@ func (i *TestExampleImplementation) TheExampleMethodFuncType(fn ExampleFuncType)
return args.Error(0) return args.Error(0)
} }
// MockTestingT mocks a test struct
type MockTestingT struct {
logfCount, errorfCount, failNowCount int
}
const mockTestingTFailNowCalled = "FailNow was called"
func (m *MockTestingT) Logf(string, ...interface{}) {
m.logfCount++
}
func (m *MockTestingT) Errorf(string, ...interface{}) {
m.errorfCount++
}
// FailNow mocks the FailNow call.
// It panics in order to mimic the FailNow behavior in the sense that
// the execution stops.
// When expecting this method, the call that invokes it should use the following code:
//
// assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {...})
func (m *MockTestingT) FailNow() {
m.failNowCount++
// this function should panic now to stop the execution as expected
panic(mockTestingTFailNowCalled)
}
/* /*
Mock Mock
*/ */
@ -119,6 +150,8 @@ func Test_Mock_Chained_On(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService = new(TestExampleImplementation) var mockedService = new(TestExampleImplementation)
// determine our current line number so we can assert the expected calls callerInfo properly
_, _, line, _ := runtime.Caller(0)
mockedService. mockedService.
On("TheExampleMethod", 1, 2, 3). On("TheExampleMethod", 1, 2, 3).
Return(0). Return(0).
@ -126,17 +159,19 @@ func Test_Mock_Chained_On(t *testing.T) {
Return(nil) Return(nil)
expectedCalls := []*Call{ expectedCalls := []*Call{
&Call{ {
Parent: &mockedService.Mock, Parent: &mockedService.Mock,
Method: "TheExampleMethod", Method: "TheExampleMethod",
Arguments: []interface{}{1, 2, 3}, Arguments: []interface{}{1, 2, 3},
ReturnArguments: []interface{}{0}, ReturnArguments: []interface{}{0},
callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+2)},
}, },
&Call{ {
Parent: &mockedService.Mock, Parent: &mockedService.Mock,
Method: "TheExampleMethod3", Method: "TheExampleMethod3",
Arguments: []interface{}{AnythingOfType("*mock.ExampleType")}, Arguments: []interface{}{AnythingOfType("*mock.ExampleType")},
ReturnArguments: []interface{}{nil}, ReturnArguments: []interface{}{nil},
callerInfo: []string{fmt.Sprintf("mock_test.go:%d", line+4)},
}, },
} }
assert.Equal(t, expectedCalls, mockedService.ExpectedCalls) assert.Equal(t, expectedCalls, mockedService.ExpectedCalls)
@ -198,6 +233,34 @@ func Test_Mock_On_WithIntArgMatcher(t *testing.T) {
}) })
} }
func TestMock_WithTest(t *testing.T) {
var (
mockedService TestExampleImplementation
mockedTest MockTestingT
)
mockedService.Test(&mockedTest)
mockedService.On("TheExampleMethod", 1, 2, 3).Return(0, nil)
// Test that on an expected call, the test was not failed
mockedService.TheExampleMethod(1, 2, 3)
// Assert that Errorf and FailNow were not called
assert.Equal(t, 0, mockedTest.errorfCount)
assert.Equal(t, 0, mockedTest.failNowCount)
// Test that on unexpected call, the mocked test was called to fail the test
assert.PanicsWithValue(t, mockTestingTFailNowCalled, func() {
mockedService.TheExampleMethod(1, 1, 1)
})
// Assert that Errorf and FailNow were called once
assert.Equal(t, 1, mockedTest.errorfCount)
assert.Equal(t, 1, mockedTest.failNowCount)
}
func Test_Mock_On_WithPtrArgMatcher(t *testing.T) { func Test_Mock_On_WithPtrArgMatcher(t *testing.T) {
var mockedService TestExampleImplementation var mockedService TestExampleImplementation
@ -1125,8 +1188,8 @@ func Test_Arguments_Diff(t *testing.T) {
diff, count = args.Diff([]interface{}{"Hello World", 456, "false"}) diff, count = args.Diff([]interface{}{"Hello World", 456, "false"})
assert.Equal(t, 2, count) assert.Equal(t, 2, count)
assert.Contains(t, diff, `%!s(int=456) != %!s(int=123)`) assert.Contains(t, diff, `(int=456) != (int=123)`)
assert.Contains(t, diff, `false != %!s(bool=true)`) assert.Contains(t, diff, `(string=false) != (bool=true)`)
} }
@ -1138,7 +1201,7 @@ func Test_Arguments_Diff_DifferentNumberOfArgs(t *testing.T) {
diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"}) diff, count = args.Diff([]interface{}{"string", 456, "false", "extra"})
assert.Equal(t, 3, count) assert.Equal(t, 3, count)
assert.Contains(t, diff, `extra != (Missing)`) assert.Contains(t, diff, `(string=extra) != (Missing)`)
} }
@ -1180,7 +1243,7 @@ func Test_Arguments_Diff_WithAnythingOfTypeArgument_Failing(t *testing.T) {
diff, count = args.Diff([]interface{}{"string", 123, true}) diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Contains(t, diff, `string != type int - %!s(int=123)`) assert.Contains(t, diff, `string != type int - (int=123)`)
} }
@ -1192,14 +1255,14 @@ func Test_Arguments_Diff_WithArgMatcher(t *testing.T) {
diff, count := args.Diff([]interface{}{"string", 124, true}) diff, count := args.Diff([]interface{}{"string", 124, true})
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Contains(t, diff, `%!s(int=124) not matched by func(int) bool`) assert.Contains(t, diff, `(int=124) not matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", false, true}) diff, count = args.Diff([]interface{}{"string", false, true})
assert.Equal(t, 1, count) assert.Equal(t, 1, count)
assert.Contains(t, diff, `%!s(bool=false) not matched by func(int) bool`) assert.Contains(t, diff, `(bool=false) not matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", 123, false}) diff, count = args.Diff([]interface{}{"string", 123, false})
assert.Contains(t, diff, `%!s(int=123) matched by func(int) bool`) assert.Contains(t, diff, `(int=123) matched by func(int) bool`)
diff, count = args.Diff([]interface{}{"string", 123, true}) diff, count = args.Diff([]interface{}{"string", 123, true})
assert.Equal(t, 0, count) assert.Equal(t, 0, count)
@ -1260,7 +1323,7 @@ func Test_Arguments_Bool(t *testing.T) {
func Test_WaitUntil_Parallel(t *testing.T) { func Test_WaitUntil_Parallel(t *testing.T) {
// make a test impl object // make a test impl object
var mockedService *TestExampleImplementation = new(TestExampleImplementation) var mockedService = new(TestExampleImplementation)
ch1 := make(chan time.Time) ch1 := make(chan time.Time)
ch2 := make(chan time.Time) ch2 := make(chan time.Time)
@ -1323,6 +1386,37 @@ func (s *timer) GetTime(i int) string {
return s.Called(i).Get(0).(string) return s.Called(i).Get(0).(string)
} }
type tCustomLogger struct {
*testing.T
logs []string
errs []string
}
func (tc *tCustomLogger) Logf(format string, args ...interface{}) {
tc.T.Logf(format, args...)
tc.logs = append(tc.logs, fmt.Sprintf(format, args...))
}
func (tc *tCustomLogger) Errorf(format string, args ...interface{}) {
tc.errs = append(tc.errs, fmt.Sprintf(format, args...))
}
func (tc *tCustomLogger) FailNow() {}
func TestLoggingAssertExpectations(t *testing.T) {
m := new(timer)
m.On("GetTime", 0).Return("")
tcl := &tCustomLogger{t, []string{}, []string{}}
AssertExpectationsForObjects(tcl, m, new(TestExampleImplementation))
require.Equal(t, 1, len(tcl.errs))
assert.Regexp(t, regexp.MustCompile("(?s)FAIL: 0 out of 1 expectation\\(s\\) were met.*The code you are testing needs to make 1 more call\\(s\\).*"), tcl.errs[0])
require.Equal(t, 2, len(tcl.logs))
assert.Regexp(t, regexp.MustCompile("(?s)FAIL:\tGetTime\\(int\\).*"), tcl.logs[0])
require.Equal(t, "Expectations didn't match for Mock: *mock.timer", tcl.logs[1])
}
func TestAfterTotalWaitTimeWhileExecution(t *testing.T) { func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
waitDuration := 1 waitDuration := 1
total, waitMs := 5, time.Millisecond*time.Duration(waitDuration) total, waitMs := 5, time.Millisecond*time.Duration(waitDuration)
@ -1342,11 +1436,64 @@ func TestAfterTotalWaitTimeWhileExecution(t *testing.T) {
elapsedTime := end.Sub(start) elapsedTime := end.Sub(start)
assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs)) assert.True(t, elapsedTime > waitMs, fmt.Sprintf("Total elapsed time:%v should be atleast greater than %v", elapsedTime, waitMs))
assert.Equal(t, total, len(results)) assert.Equal(t, total, len(results))
for i, _ := range results { for i := range results {
assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same") assert.Equal(t, fmt.Sprintf("Time%d", i), results[i], "Return value of method should be same")
} }
} }
func TestArgumentMatcherToPrintMismatch(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(
`\s+mock: Unexpected Method Call\s+-*\s+GetTime\(int\)\s+0: 1\s+The closest call I have is:\s+GetTime\(mock.argumentMatcher\)\s+0: mock.argumentMatcher\{.*?\}\s+Diff:.*\(int=1\) not matched by func\(int\) bool`)
assert.Regexp(t, matchingExp, r)
}
}()
m := new(timer)
m.On("GetTime", MatchedBy(func(i int) bool { return false })).Return("SomeTime").Once()
res := m.GetTime(1)
require.Equal(t, "SomeTime", res)
m.AssertExpectations(t)
}
func TestClosestCallMismatchedArgumentInformationShowsTheClosest(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`TheExampleMethod(int,int,int)`, `0: 1\s+1: 1\s+2: 2`, `0: 1\s+1: 1\s+2: 1`, `0: PASS: \(int=1\) == \(int=1\)\s+1: PASS: \(int=1\) == \(int=1\)\s+2: FAIL: \(int=2\) != \(int=1\)`))
assert.Regexp(t, matchingExp, r)
}
}()
m := new(TestExampleImplementation)
m.On("TheExampleMethod", 1, 1, 1).Return(1, nil).Once()
m.On("TheExampleMethod", 2, 2, 2).Return(2, nil).Once()
m.TheExampleMethod(1, 1, 2)
}
func TestClosestCallMismatchedArgumentValueInformation(t *testing.T) {
defer func() {
if r := recover(); r != nil {
matchingExp := regexp.MustCompile(unexpectedCallRegex(`GetTime(int)`, "0: 1", "0: 999", `0: FAIL: \(int=1\) != \(int=999\)`))
assert.Regexp(t, matchingExp, r)
}
}()
m := new(timer)
m.On("GetTime", 999).Return("SomeTime").Once()
_ = m.GetTime(1)
}
func unexpectedCallRegex(method, calledArg, expectedArg, diff string) string {
rMethod := regexp.QuoteMeta(method)
return fmt.Sprintf(`\s+mock: Unexpected Method Call\s+-*\s+%s\s+%s\s+The closest call I have is:\s+%s\s+%s\s+Diff: %s`,
rMethod, calledArg, rMethod, expectedArg, diff)
}
//go:noinline
func ConcurrencyTestMethod(m *Mock) { func ConcurrencyTestMethod(m *Mock) {
m.Called() m.Called()
} }

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
{{.Comment}} {{.Comment}}
func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { func {{.DocInfo.Name}}(t TestingT, {{.Params}}) {
if !assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return }
t.FailNow() if h, ok := t.(tHelper); ok { h.Helper() }
} t.FailNow()
} }

View file

@ -14,11 +14,17 @@ import (
// Condition uses a Comparison to assert a complex condition. // Condition uses a Comparison to assert a complex condition.
func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Condition(a.t, comp, msgAndArgs...) Condition(a.t, comp, msgAndArgs...)
} }
// Conditionf uses a Comparison to assert a complex condition. // Conditionf uses a Comparison to assert a complex condition.
func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) { func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Conditionf(a.t, comp, msg, args...) Conditionf(a.t, comp, msg, args...)
} }
@ -28,9 +34,10 @@ func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args ...inte
// a.Contains("Hello World", "World") // a.Contains("Hello World", "World")
// a.Contains(["Hello", "World"], "World") // a.Contains(["Hello", "World"], "World")
// a.Contains({"Hello": "World"}, "Hello") // a.Contains({"Hello": "World"}, "Hello")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Contains(a.t, s, contains, msgAndArgs...) Contains(a.t, s, contains, msgAndArgs...)
} }
@ -40,19 +47,26 @@ func (a *Assertions) Contains(s interface{}, contains interface{}, msgAndArgs ..
// a.Containsf("Hello World", "World", "error message %s", "formatted") // a.Containsf("Hello World", "World", "error message %s", "formatted")
// a.Containsf(["Hello", "World"], "World", "error message %s", "formatted") // a.Containsf(["Hello", "World"], "World", "error message %s", "formatted")
// a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted") // a.Containsf({"Hello": "World"}, "Hello", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) { func (a *Assertions) Containsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Containsf(a.t, s, contains, msg, args...) Containsf(a.t, s, contains, msg, args...)
} }
// DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. // DirExists checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) { func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
DirExists(a.t, path, msgAndArgs...) DirExists(a.t, path, msgAndArgs...)
} }
// DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists. // DirExistsf checks whether a directory exists in the given path. It also fails if the path is a file rather a directory or there is an error checking whether it exists.
func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) { func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
DirExistsf(a.t, path, msg, args...) DirExistsf(a.t, path, msg, args...)
} }
@ -60,10 +74,11 @@ func (a *Assertions) DirExistsf(path string, msg string, args ...interface{}) {
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match. // the number of appearances of each of them in both lists should match.
// //
// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])) // a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2])
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) { func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ElementsMatch(a.t, listA, listB, msgAndArgs...) ElementsMatch(a.t, listA, listB, msgAndArgs...)
} }
@ -71,10 +86,11 @@ func (a *Assertions) ElementsMatch(listA interface{}, listB interface{}, msgAndA
// listB(array, slice...) ignoring the order of the elements. If there are duplicate elements, // listB(array, slice...) ignoring the order of the elements. If there are duplicate elements,
// the number of appearances of each of them in both lists should match. // the number of appearances of each of them in both lists should match.
// //
// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")) // a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) { func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
ElementsMatchf(a.t, listA, listB, msg, args...) ElementsMatchf(a.t, listA, listB, msg, args...)
} }
@ -82,9 +98,10 @@ func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}, msg st
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// a.Empty(obj) // a.Empty(obj)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Empty(a.t, object, msgAndArgs...) Empty(a.t, object, msgAndArgs...)
} }
@ -92,9 +109,10 @@ func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
// a slice or a channel with len == 0. // a slice or a channel with len == 0.
// //
// a.Emptyf(obj, "error message %s", "formatted") // a.Emptyf(obj, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) { func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Emptyf(a.t, object, msg, args...) Emptyf(a.t, object, msg, args...)
} }
@ -102,12 +120,13 @@ func (a *Assertions) Emptyf(object interface{}, msg string, args ...interface{})
// //
// a.Equal(123, 123) // a.Equal(123, 123)
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail. // cannot be determined and will always fail.
func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Equal(a.t, expected, actual, msgAndArgs...) Equal(a.t, expected, actual, msgAndArgs...)
} }
@ -116,9 +135,10 @@ func (a *Assertions) Equal(expected interface{}, actual interface{}, msgAndArgs
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// a.EqualError(err, expectedErrorString) // a.EqualError(err, expectedErrorString)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) { func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualError(a.t, theError, errString, msgAndArgs...) EqualError(a.t, theError, errString, msgAndArgs...)
} }
@ -127,9 +147,10 @@ func (a *Assertions) EqualError(theError error, errString string, msgAndArgs ...
// //
// actualObj, err := SomeFunction() // actualObj, err := SomeFunction()
// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") // a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) { func (a *Assertions) EqualErrorf(theError error, errString string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualErrorf(a.t, theError, errString, msg, args...) EqualErrorf(a.t, theError, errString, msg, args...)
} }
@ -137,9 +158,10 @@ func (a *Assertions) EqualErrorf(theError error, errString string, msg string, a
// and equal. // and equal.
// //
// a.EqualValues(uint32(123), int32(123)) // a.EqualValues(uint32(123), int32(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualValues(a.t, expected, actual, msgAndArgs...) EqualValues(a.t, expected, actual, msgAndArgs...)
} }
@ -147,9 +169,10 @@ func (a *Assertions) EqualValues(expected interface{}, actual interface{}, msgAn
// and equal. // and equal.
// //
// a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123)) // a.EqualValuesf(uint32(123, "error message %s", "formatted"), int32(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
EqualValuesf(a.t, expected, actual, msg, args...) EqualValuesf(a.t, expected, actual, msg, args...)
} }
@ -157,12 +180,13 @@ func (a *Assertions) EqualValuesf(expected interface{}, actual interface{}, msg
// //
// a.Equalf(123, 123, "error message %s", "formatted") // a.Equalf(123, 123, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). Function equality // referenced values (as opposed to the memory addresses). Function equality
// cannot be determined and will always fail. // cannot be determined and will always fail.
func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) { func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Equalf(a.t, expected, actual, msg, args...) Equalf(a.t, expected, actual, msg, args...)
} }
@ -172,9 +196,10 @@ func (a *Assertions) Equalf(expected interface{}, actual interface{}, msg string
// if a.Error(err) { // if a.Error(err) {
// assert.Equal(t, expectedError, err) // assert.Equal(t, expectedError, err)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Error(a.t, err, msgAndArgs...) Error(a.t, err, msgAndArgs...)
} }
@ -184,115 +209,150 @@ func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
// if a.Errorf(err, "error message %s", "formatted") { // if a.Errorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedErrorf, err) // assert.Equal(t, expectedErrorf, err)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Errorf(err error, msg string, args ...interface{}) { func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Errorf(a.t, err, msg, args...) Errorf(a.t, err, msg, args...)
} }
// Exactly asserts that two objects are equal in value and type. // Exactly asserts that two objects are equal in value and type.
// //
// a.Exactly(int32(123), int64(123)) // a.Exactly(int32(123), int64(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Exactly(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Exactly(a.t, expected, actual, msgAndArgs...) Exactly(a.t, expected, actual, msgAndArgs...)
} }
// Exactlyf asserts that two objects are equal in value and type. // Exactlyf asserts that two objects are equal in value and type.
// //
// a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123)) // a.Exactlyf(int32(123, "error message %s", "formatted"), int64(123))
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) { func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Exactlyf(a.t, expected, actual, msg, args...) Exactlyf(a.t, expected, actual, msg, args...)
} }
// Fail reports a failure through // Fail reports a failure through
func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Fail(a.t, failureMessage, msgAndArgs...) Fail(a.t, failureMessage, msgAndArgs...)
} }
// FailNow fails test // FailNow fails test
func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FailNow(a.t, failureMessage, msgAndArgs...) FailNow(a.t, failureMessage, msgAndArgs...)
} }
// FailNowf fails test // FailNowf fails test
func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) { func (a *Assertions) FailNowf(failureMessage string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FailNowf(a.t, failureMessage, msg, args...) FailNowf(a.t, failureMessage, msg, args...)
} }
// Failf reports a failure through // Failf reports a failure through
func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) { func (a *Assertions) Failf(failureMessage string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Failf(a.t, failureMessage, msg, args...) Failf(a.t, failureMessage, msg, args...)
} }
// False asserts that the specified value is false. // False asserts that the specified value is false.
// //
// a.False(myBool) // a.False(myBool)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
False(a.t, value, msgAndArgs...) False(a.t, value, msgAndArgs...)
} }
// Falsef asserts that the specified value is false. // Falsef asserts that the specified value is false.
// //
// a.Falsef(myBool, "error message %s", "formatted") // a.Falsef(myBool, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) { func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Falsef(a.t, value, msg, args...) Falsef(a.t, value, msg, args...)
} }
// FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. // FileExists checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) { func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FileExists(a.t, path, msgAndArgs...) FileExists(a.t, path, msgAndArgs...)
} }
// FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file. // FileExistsf checks whether a file exists in the given path. It also fails if the path points to a directory or there is an error when trying to check the file.
func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) { func (a *Assertions) FileExistsf(path string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
FileExistsf(a.t, path, msg, args...) FileExistsf(a.t, path, msg, args...)
} }
// HTTPBodyContains asserts that a specified handler returns a // HTTPBodyContains asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// a.HTTPBodyContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") // a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...)
} }
// HTTPBodyContainsf asserts that a specified handler returns a // HTTPBodyContainsf asserts that a specified handler returns a
// body that contains a string. // body that contains a string.
// //
// a.HTTPBodyContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // a.HTTPBodyContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...) HTTPBodyContainsf(a.t, handler, method, url, values, str, msg, args...)
} }
// HTTPBodyNotContains asserts that a specified handler returns a // HTTPBodyNotContains asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// a.HTTPBodyNotContains(myHandler, "www.google.com", nil, "I'm Feeling Lucky") // a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...)
} }
// HTTPBodyNotContainsf asserts that a specified handler returns a // HTTPBodyNotContainsf asserts that a specified handler returns a
// body that does not contain a string. // body that does not contain a string.
// //
// a.HTTPBodyNotContainsf(myHandler, "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted") // a.HTTPBodyNotContainsf(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky", "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...) HTTPBodyNotContainsf(a.t, handler, method, url, values, str, msg, args...)
} }
@ -302,6 +362,9 @@ func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, method strin
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPError(a.t, handler, method, url, values, msgAndArgs...) HTTPError(a.t, handler, method, url, values, msgAndArgs...)
} }
@ -311,6 +374,9 @@ func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, url stri
// //
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). // Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPErrorf(a.t, handler, method, url, values, msg, args...) HTTPErrorf(a.t, handler, method, url, values, msg, args...)
} }
@ -320,6 +386,9 @@ func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string, url str
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...)
} }
@ -329,6 +398,9 @@ func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method string, url s
// //
// Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false). // Returns whether the assertion was successful (true, "error message %s", "formatted") or not (false).
func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPRedirectf(a.t, handler, method, url, values, msg, args...) HTTPRedirectf(a.t, handler, method, url, values, msg, args...)
} }
@ -338,6 +410,9 @@ func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method string, url
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...)
} }
@ -347,6 +422,9 @@ func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string, url st
// //
// Returns whether the assertion was successful (true) or not (false). // Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
HTTPSuccessf(a.t, handler, method, url, values, msg, args...) HTTPSuccessf(a.t, handler, method, url, values, msg, args...)
} }
@ -354,6 +432,9 @@ func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method string, url s
// //
// a.Implements((*MyInterface)(nil), new(MyObject)) // a.Implements((*MyInterface)(nil), new(MyObject))
func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Implements(interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Implements(a.t, interfaceObject, object, msgAndArgs...) Implements(a.t, interfaceObject, object, msgAndArgs...)
} }
@ -361,96 +442,129 @@ func (a *Assertions) Implements(interfaceObject interface{}, object interface{},
// //
// a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject)) // a.Implementsf((*MyInterface, "error message %s", "formatted")(nil), new(MyObject))
func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { func (a *Assertions) Implementsf(interfaceObject interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Implementsf(a.t, interfaceObject, object, msg, args...) Implementsf(a.t, interfaceObject, object, msg, args...)
} }
// InDelta asserts that the two numerals are within delta of each other. // InDelta asserts that the two numerals are within delta of each other.
// //
// a.InDelta(math.Pi, (22 / 7.0), 0.01) // a.InDelta(math.Pi, (22 / 7.0), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { func (a *Assertions) InDelta(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDelta(a.t, expected, actual, delta, msgAndArgs...) InDelta(a.t, expected, actual, delta, msgAndArgs...)
} }
// InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. // InDeltaMapValues is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { func (a *Assertions) InDeltaMapValues(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...) InDeltaMapValues(a.t, expected, actual, delta, msgAndArgs...)
} }
// InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys. // InDeltaMapValuesf is the same as InDelta, but it compares all values between two maps. Both maps must have exactly the same keys.
func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...) InDeltaMapValuesf(a.t, expected, actual, delta, msg, args...)
} }
// InDeltaSlice is the same as InDelta, except it compares two slices. // InDeltaSlice is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { func (a *Assertions) InDeltaSlice(expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...) InDeltaSlice(a.t, expected, actual, delta, msgAndArgs...)
} }
// InDeltaSlicef is the same as InDelta, except it compares two slices. // InDeltaSlicef is the same as InDelta, except it compares two slices.
func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { func (a *Assertions) InDeltaSlicef(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaSlicef(a.t, expected, actual, delta, msg, args...) InDeltaSlicef(a.t, expected, actual, delta, msg, args...)
} }
// InDeltaf asserts that the two numerals are within delta of each other. // InDeltaf asserts that the two numerals are within delta of each other.
// //
// a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01) // a.InDeltaf(math.Pi, (22 / 7.0, "error message %s", "formatted"), 0.01)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InDeltaf(a.t, expected, actual, delta, msg, args...) InDeltaf(a.t, expected, actual, delta, msg, args...)
} }
// InEpsilon asserts that expected and actual have a relative error less than epsilon // InEpsilon asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { func (a *Assertions) InEpsilon(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...) InEpsilon(a.t, expected, actual, epsilon, msgAndArgs...)
} }
// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. // InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { func (a *Assertions) InEpsilonSlice(expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...)
} }
// InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices. // InEpsilonSlicef is the same as InEpsilon, except it compares each value from two slices.
func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...)
} }
// InEpsilonf asserts that expected and actual have a relative error less than epsilon // InEpsilonf asserts that expected and actual have a relative error less than epsilon
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
InEpsilonf(a.t, expected, actual, epsilon, msg, args...) InEpsilonf(a.t, expected, actual, epsilon, msg, args...)
} }
// IsType asserts that the specified objects are of the same type. // IsType asserts that the specified objects are of the same type.
func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { func (a *Assertions) IsType(expectedType interface{}, object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsType(a.t, expectedType, object, msgAndArgs...) IsType(a.t, expectedType, object, msgAndArgs...)
} }
// IsTypef asserts that the specified objects are of the same type. // IsTypef asserts that the specified objects are of the same type.
func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) { func (a *Assertions) IsTypef(expectedType interface{}, object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
IsTypef(a.t, expectedType, object, msg, args...) IsTypef(a.t, expectedType, object, msg, args...)
} }
// JSONEq asserts that two JSON strings are equivalent. // JSONEq asserts that two JSON strings are equivalent.
// //
// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) // a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) { func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
JSONEq(a.t, expected, actual, msgAndArgs...) JSONEq(a.t, expected, actual, msgAndArgs...)
} }
// JSONEqf asserts that two JSON strings are equivalent. // JSONEqf asserts that two JSON strings are equivalent.
// //
// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") // a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) { func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
JSONEqf(a.t, expected, actual, msg, args...) JSONEqf(a.t, expected, actual, msg, args...)
} }
@ -458,9 +572,10 @@ func (a *Assertions) JSONEqf(expected string, actual string, msg string, args ..
// Len also fails if the object has a type that len() not accept. // Len also fails if the object has a type that len() not accept.
// //
// a.Len(mySlice, 3) // a.Len(mySlice, 3)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) { func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Len(a.t, object, length, msgAndArgs...) Len(a.t, object, length, msgAndArgs...)
} }
@ -468,27 +583,30 @@ func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...interface
// Lenf also fails if the object has a type that len() not accept. // Lenf also fails if the object has a type that len() not accept.
// //
// a.Lenf(mySlice, 3, "error message %s", "formatted") // a.Lenf(mySlice, 3, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) { func (a *Assertions) Lenf(object interface{}, length int, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Lenf(a.t, object, length, msg, args...) Lenf(a.t, object, length, msg, args...)
} }
// Nil asserts that the specified object is nil. // Nil asserts that the specified object is nil.
// //
// a.Nil(err) // a.Nil(err)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Nil(a.t, object, msgAndArgs...) Nil(a.t, object, msgAndArgs...)
} }
// Nilf asserts that the specified object is nil. // Nilf asserts that the specified object is nil.
// //
// a.Nilf(err, "error message %s", "formatted") // a.Nilf(err, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) { func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Nilf(a.t, object, msg, args...) Nilf(a.t, object, msg, args...)
} }
@ -498,9 +616,10 @@ func (a *Assertions) Nilf(object interface{}, msg string, args ...interface{}) {
// if a.NoError(err) { // if a.NoError(err) {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoError(a.t, err, msgAndArgs...) NoError(a.t, err, msgAndArgs...)
} }
@ -510,9 +629,10 @@ func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
// if a.NoErrorf(err, "error message %s", "formatted") { // if a.NoErrorf(err, "error message %s", "formatted") {
// assert.Equal(t, expectedObj, actualObj) // assert.Equal(t, expectedObj, actualObj)
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) { func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NoErrorf(a.t, err, msg, args...) NoErrorf(a.t, err, msg, args...)
} }
@ -522,9 +642,10 @@ func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
// a.NotContains("Hello World", "Earth") // a.NotContains("Hello World", "Earth")
// a.NotContains(["Hello", "World"], "Earth") // a.NotContains(["Hello", "World"], "Earth")
// a.NotContains({"Hello": "World"}, "Earth") // a.NotContains({"Hello": "World"}, "Earth")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotContains(a.t, s, contains, msgAndArgs...) NotContains(a.t, s, contains, msgAndArgs...)
} }
@ -534,9 +655,10 @@ func (a *Assertions) NotContains(s interface{}, contains interface{}, msgAndArgs
// a.NotContainsf("Hello World", "Earth", "error message %s", "formatted") // a.NotContainsf("Hello World", "Earth", "error message %s", "formatted")
// a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted") // a.NotContainsf(["Hello", "World"], "Earth", "error message %s", "formatted")
// a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted") // a.NotContainsf({"Hello": "World"}, "Earth", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) { func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotContainsf(a.t, s, contains, msg, args...) NotContainsf(a.t, s, contains, msg, args...)
} }
@ -546,9 +668,10 @@ func (a *Assertions) NotContainsf(s interface{}, contains interface{}, msg strin
// if a.NotEmpty(obj) { // if a.NotEmpty(obj) {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEmpty(a.t, object, msgAndArgs...) NotEmpty(a.t, object, msgAndArgs...)
} }
@ -558,9 +681,10 @@ func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) {
// if a.NotEmptyf(obj, "error message %s", "formatted") { // if a.NotEmptyf(obj, "error message %s", "formatted") {
// assert.Equal(t, "two", obj[1]) // assert.Equal(t, "two", obj[1])
// } // }
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) { func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEmptyf(a.t, object, msg, args...) NotEmptyf(a.t, object, msg, args...)
} }
@ -568,11 +692,12 @@ func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...interface
// //
// a.NotEqual(obj1, obj2) // a.NotEqual(obj1, obj2)
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqual(a.t, expected, actual, msgAndArgs...) NotEqual(a.t, expected, actual, msgAndArgs...)
} }
@ -580,47 +705,52 @@ func (a *Assertions) NotEqual(expected interface{}, actual interface{}, msgAndAr
// //
// a.NotEqualf(obj1, obj2, "error message %s", "formatted") // a.NotEqualf(obj1, obj2, "error message %s", "formatted")
// //
// Returns whether the assertion was successful (true) or not (false).
//
// Pointer variable equality is determined based on the equality of the // Pointer variable equality is determined based on the equality of the
// referenced values (as opposed to the memory addresses). // referenced values (as opposed to the memory addresses).
func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) { func (a *Assertions) NotEqualf(expected interface{}, actual interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotEqualf(a.t, expected, actual, msg, args...) NotEqualf(a.t, expected, actual, msg, args...)
} }
// NotNil asserts that the specified object is not nil. // NotNil asserts that the specified object is not nil.
// //
// a.NotNil(err) // a.NotNil(err)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotNil(a.t, object, msgAndArgs...) NotNil(a.t, object, msgAndArgs...)
} }
// NotNilf asserts that the specified object is not nil. // NotNilf asserts that the specified object is not nil.
// //
// a.NotNilf(err, "error message %s", "formatted") // a.NotNilf(err, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) { func (a *Assertions) NotNilf(object interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotNilf(a.t, object, msg, args...) NotNilf(a.t, object, msg, args...)
} }
// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// a.NotPanics(func(){ RemainCalm() }) // a.NotPanics(func(){ RemainCalm() })
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotPanics(a.t, f, msgAndArgs...) NotPanics(a.t, f, msgAndArgs...)
} }
// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. // NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic.
// //
// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") // a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotPanicsf(a.t, f, msg, args...) NotPanicsf(a.t, f, msg, args...)
} }
@ -628,9 +758,10 @@ func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args ...inte
// //
// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") // a.NotRegexp(regexp.MustCompile("starts"), "it's starting")
// a.NotRegexp("^start", "it's not starting") // a.NotRegexp("^start", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotRegexp(a.t, rx, str, msgAndArgs...) NotRegexp(a.t, rx, str, msgAndArgs...)
} }
@ -638,9 +769,10 @@ func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndArgs ...in
// //
// a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting") // a.NotRegexpf(regexp.MustCompile("starts", "error message %s", "formatted"), "it's starting")
// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") // a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotRegexpf(a.t, rx, str, msg, args...) NotRegexpf(a.t, rx, str, msg, args...)
} }
@ -648,9 +780,10 @@ func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg string, arg
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") // a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotSubset(a.t, list, subset, msgAndArgs...) NotSubset(a.t, list, subset, msgAndArgs...)
} }
@ -658,28 +791,36 @@ func (a *Assertions) NotSubset(list interface{}, subset interface{}, msgAndArgs
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted") // a.NotSubsetf([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotSubsetf(a.t, list, subset, msg, args...) NotSubsetf(a.t, list, subset, msg, args...)
} }
// NotZero asserts that i is not the zero value for its type and returns the truth. // NotZero asserts that i is not the zero value for its type.
func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotZero(a.t, i, msgAndArgs...) NotZero(a.t, i, msgAndArgs...)
} }
// NotZerof asserts that i is not the zero value for its type and returns the truth. // NotZerof asserts that i is not the zero value for its type.
func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) { func (a *Assertions) NotZerof(i interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
NotZerof(a.t, i, msg, args...) NotZerof(a.t, i, msg, args...)
} }
// Panics asserts that the code inside the specified PanicTestFunc panics. // Panics asserts that the code inside the specified PanicTestFunc panics.
// //
// a.Panics(func(){ GoCrazy() }) // a.Panics(func(){ GoCrazy() })
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Panics(a.t, f, msgAndArgs...) Panics(a.t, f, msgAndArgs...)
} }
@ -687,9 +828,10 @@ func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) {
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) // a.PanicsWithValue("crazy error", func(){ GoCrazy() })
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
PanicsWithValue(a.t, expected, f, msgAndArgs...) PanicsWithValue(a.t, expected, f, msgAndArgs...)
} }
@ -697,18 +839,20 @@ func (a *Assertions) PanicsWithValue(expected interface{}, f assert.PanicTestFun
// the recovered panic value equals the expected panic value. // the recovered panic value equals the expected panic value.
// //
// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") // a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
PanicsWithValuef(a.t, expected, f, msg, args...) PanicsWithValuef(a.t, expected, f, msg, args...)
} }
// Panicsf asserts that the code inside the specified PanicTestFunc panics. // Panicsf asserts that the code inside the specified PanicTestFunc panics.
// //
// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") // a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) { func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Panicsf(a.t, f, msg, args...) Panicsf(a.t, f, msg, args...)
} }
@ -716,9 +860,10 @@ func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args ...interfa
// //
// a.Regexp(regexp.MustCompile("start"), "it's starting") // a.Regexp(regexp.MustCompile("start"), "it's starting")
// a.Regexp("start...$", "it's not starting") // a.Regexp("start...$", "it's not starting")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Regexp(a.t, rx, str, msgAndArgs...) Regexp(a.t, rx, str, msgAndArgs...)
} }
@ -726,9 +871,10 @@ func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...inter
// //
// a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting") // a.Regexpf(regexp.MustCompile("start", "error message %s", "formatted"), "it's starting")
// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") // a.Regexpf("start...$", "it's not starting", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) { func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Regexpf(a.t, rx, str, msg, args...) Regexpf(a.t, rx, str, msg, args...)
} }
@ -736,9 +882,10 @@ func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string, args .
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") // a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Subset(a.t, list, subset, msgAndArgs...) Subset(a.t, list, subset, msgAndArgs...)
} }
@ -746,54 +893,65 @@ func (a *Assertions) Subset(list interface{}, subset interface{}, msgAndArgs ...
// elements given in the specified subset(array, slice...). // elements given in the specified subset(array, slice...).
// //
// a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted") // a.Subsetf([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]", "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) { func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Subsetf(a.t, list, subset, msg, args...) Subsetf(a.t, list, subset, msg, args...)
} }
// True asserts that the specified value is true. // True asserts that the specified value is true.
// //
// a.True(myBool) // a.True(myBool)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
True(a.t, value, msgAndArgs...) True(a.t, value, msgAndArgs...)
} }
// Truef asserts that the specified value is true. // Truef asserts that the specified value is true.
// //
// a.Truef(myBool, "error message %s", "formatted") // a.Truef(myBool, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) Truef(value bool, msg string, args ...interface{}) { func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Truef(a.t, value, msg, args...) Truef(a.t, value, msg, args...)
} }
// WithinDuration asserts that the two times are within duration delta of each other. // WithinDuration asserts that the two times are within duration delta of each other.
// //
// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) // a.WithinDuration(time.Now(), time.Now(), 10*time.Second)
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { func (a *Assertions) WithinDuration(expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
WithinDuration(a.t, expected, actual, delta, msgAndArgs...) WithinDuration(a.t, expected, actual, delta, msgAndArgs...)
} }
// WithinDurationf asserts that the two times are within duration delta of each other. // WithinDurationf asserts that the two times are within duration delta of each other.
// //
// a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted") // a.WithinDurationf(time.Now(), time.Now(), 10*time.Second, "error message %s", "formatted")
//
// Returns whether the assertion was successful (true) or not (false).
func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { func (a *Assertions) WithinDurationf(expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
WithinDurationf(a.t, expected, actual, delta, msg, args...) WithinDurationf(a.t, expected, actual, delta, msg, args...)
} }
// Zero asserts that i is the zero value for its type and returns the truth. // Zero asserts that i is the zero value for its type.
func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Zero(a.t, i, msgAndArgs...) Zero(a.t, i, msgAndArgs...)
} }
// Zerof asserts that i is the zero value for its type and returns the truth. // Zerof asserts that i is the zero value for its type.
func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) { func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{}) {
if h, ok := a.t.(tHelper); ok {
h.Helper()
}
Zerof(a.t, i, msg, args...) Zerof(a.t, i, msg, args...)
} }

View file

@ -1,4 +1,5 @@
{{.CommentWithoutT "a"}} {{.CommentWithoutT "a"}}
func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {
if h, ok := a.t.(tHelper); ok { h.Helper() }
{{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) {{.DocInfo.Name}}(a.t, {{.ForwardedParams}})
} }

View file

@ -6,4 +6,24 @@ type TestingT interface {
FailNow() FailNow()
} }
type tHelper interface {
Helper()
}
// ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful
// for table driven tests.
type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{})
// ValueAssertionFunc is a common function prototype when validating a single value. Can be useful
// for table driven tests.
type ValueAssertionFunc func(TestingT, interface{}, ...interface{})
// BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful
// for table driven tests.
type BoolAssertionFunc func(TestingT, bool, ...interface{})
// ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful
// for table driven tests.
type ErrorAssertionFunc func(TestingT, error, ...interface{})
//go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs //go:generate go run ../_codegen/main.go -output-package=require -template=require.go.tmpl -include-format-funcs

View file

@ -1,6 +1,7 @@
package require package require
import ( import (
"encoding/json"
"errors" "errors"
"testing" "testing"
"time" "time"
@ -367,3 +368,199 @@ func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
t.Error("Check should fail") t.Error("Check should fail")
} }
} }
func ExampleComparisonAssertionFunc() {
t := &testing.T{} // provided by test
adder := func(x, y int) int {
return x + y
}
type args struct {
x int
y int
}
tests := []struct {
name string
args args
expect int
assertion ComparisonAssertionFunc
}{
{"2+2=4", args{2, 2}, 4, Equal},
{"2+2!=5", args{2, 2}, 5, NotEqual},
{"2+3==5", args{2, 3}, 5, Exactly},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, adder(tt.args.x, tt.args.y))
})
}
}
func TestComparisonAssertionFunc(t *testing.T) {
type iface interface {
Name() string
}
tests := []struct {
name string
expect interface{}
got interface{}
assertion ComparisonAssertionFunc
}{
{"implements", (*iface)(nil), t, Implements},
{"isType", (*testing.T)(nil), t, IsType},
{"equal", t, t, Equal},
{"equalValues", t, t, EqualValues},
{"exactly", t, t, Exactly},
{"notEqual", t, nil, NotEqual},
{"notContains", []int{1, 2, 3}, 4, NotContains},
{"subset", []int{1, 2, 3, 4}, []int{2, 3}, Subset},
{"notSubset", []int{1, 2, 3, 4}, []int{0, 3}, NotSubset},
{"elementsMatch", []byte("abc"), []byte("bac"), ElementsMatch},
{"regexp", "^t.*y$", "testify", Regexp},
{"notRegexp", "^t.*y$", "Testify", NotRegexp},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.expect, tt.got)
})
}
}
func ExampleValueAssertionFunc() {
t := &testing.T{} // provided by test
dumbParse := func(input string) interface{} {
var x interface{}
json.Unmarshal([]byte(input), &x)
return x
}
tests := []struct {
name string
arg string
assertion ValueAssertionFunc
}{
{"true is not nil", "true", NotNil},
{"empty string is nil", "", Nil},
{"zero is not nil", "0", NotNil},
{"zero is zero", "0", Zero},
{"false is zero", "false", Zero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, dumbParse(tt.arg))
})
}
}
func TestValueAssertionFunc(t *testing.T) {
tests := []struct {
name string
value interface{}
assertion ValueAssertionFunc
}{
{"notNil", true, NotNil},
{"nil", nil, Nil},
{"empty", []int{}, Empty},
{"notEmpty", []int{1}, NotEmpty},
{"zero", false, Zero},
{"notZero", 42, NotZero},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleBoolAssertionFunc() {
t := &testing.T{} // provided by test
isOkay := func(x int) bool {
return x >= 42
}
tests := []struct {
name string
arg int
assertion BoolAssertionFunc
}{
{"-1 is bad", -1, False},
{"42 is good", 42, True},
{"41 is bad", 41, False},
{"45 is cool", 45, True},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, isOkay(tt.arg))
})
}
}
func TestBoolAssertionFunc(t *testing.T) {
tests := []struct {
name string
value bool
assertion BoolAssertionFunc
}{
{"true", true, True},
{"false", false, False},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.value)
})
}
}
func ExampleErrorAssertionFunc() {
t := &testing.T{} // provided by test
dumbParseNum := func(input string, v interface{}) error {
return json.Unmarshal([]byte(input), v)
}
tests := []struct {
name string
arg string
assertion ErrorAssertionFunc
}{
{"1.2 is number", "1.2", NoError},
{"1.2.3 not number", "1.2.3", Error},
{"true is not number", "true", Error},
{"3 is number", "3", NoError},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var x float64
tt.assertion(t, dumbParseNum(tt.arg, &x))
})
}
}
func TestErrorAssertionFunc(t *testing.T) {
tests := []struct {
name string
err error
assertion ErrorAssertionFunc
}{
{"noError", nil, NoError},
{"error", errors.New("whoops"), Error},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.assertion(t, tt.err)
})
}
}

View file

@ -55,10 +55,32 @@ func (suite *Suite) Assert() *assert.Assertions {
return suite.Assertions return suite.Assertions
} }
func failOnPanic(t *testing.T) {
r := recover()
if r != nil {
t.Errorf("test panicked: %v", r)
t.FailNow()
}
}
// Run provides suite functionality around golang subtests. It should be
// called in place of t.Run(name, func(t *testing.T)) in test suite code.
// The passed-in func will be executed as a subtest with a fresh instance of t.
// Provides compatibility with go test pkg -run TestSuite/TestName/SubTestName.
func (suite *Suite) Run(name string, subtest func()) bool {
oldT := suite.T()
defer suite.SetT(oldT)
return oldT.Run(name, func(t *testing.T) {
suite.SetT(t)
subtest()
})
}
// Run takes a testing suite and runs all of the tests attached // Run takes a testing suite and runs all of the tests attached
// to it. // to it.
func Run(t *testing.T, suite TestingSuite) { func Run(t *testing.T, suite TestingSuite) {
suite.SetT(t) suite.SetT(t)
defer failOnPanic(t)
if setupAllSuite, ok := suite.(SetupAllSuite); ok { if setupAllSuite, ok := suite.(SetupAllSuite); ok {
setupAllSuite.SetupSuite() setupAllSuite.SetupSuite()
@ -84,6 +106,8 @@ func Run(t *testing.T, suite TestingSuite) {
F: func(t *testing.T) { F: func(t *testing.T) {
parentT := suite.T() parentT := suite.T()
suite.SetT(t) suite.SetT(t)
defer failOnPanic(t)
if setupTestSuite, ok := suite.(SetupTestSuite); ok { if setupTestSuite, ok := suite.(SetupTestSuite); ok {
setupTestSuite.SetupTest() setupTestSuite.SetupTest()
} }

View file

@ -42,6 +42,99 @@ func (s *SuiteRequireTwice) TestRequireTwo() {
r.Equal(1, 2) r.Equal(1, 2)
} }
type panickingSuite struct {
Suite
panicInSetupSuite bool
panicInSetupTest bool
panicInBeforeTest bool
panicInTest bool
panicInAfterTest bool
panicInTearDownTest bool
panicInTearDownSuite bool
}
func (s *panickingSuite) SetupSuite() {
if s.panicInSetupSuite {
panic("oops in setup suite")
}
}
func (s *panickingSuite) SetupTest() {
if s.panicInSetupTest {
panic("oops in setup test")
}
}
func (s *panickingSuite) BeforeTest(_, _ string) {
if s.panicInBeforeTest {
panic("oops in before test")
}
}
func (s *panickingSuite) Test() {
if s.panicInTest {
panic("oops in test")
}
}
func (s *panickingSuite) AfterTest(_, _ string) {
if s.panicInAfterTest {
panic("oops in after test")
}
}
func (s *panickingSuite) TearDownTest() {
if s.panicInTearDownTest {
panic("oops in tear down test")
}
}
func (s *panickingSuite) TearDownSuite() {
if s.panicInTearDownSuite {
panic("oops in tear down suite")
}
}
func TestSuiteRecoverPanic(t *testing.T) {
ok := true
panickingTests := []testing.InternalTest{
{
Name: "TestPanicInSetupSuite",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupSuite: true}) },
},
{
Name: "TestPanicInSetupTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInSetupTest: true}) },
},
{
Name: "TestPanicInBeforeTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInBeforeTest: true}) },
},
{
Name: "TestPanicInTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTest: true}) },
},
{
Name: "TestPanicInAfterTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInAfterTest: true}) },
},
{
Name: "TestPanicInTearDownTest",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownTest: true}) },
},
{
Name: "TestPanicInTearDownSuite",
F: func(t *testing.T) { Run(t, &panickingSuite{panicInTearDownSuite: true}) },
},
}
require.NotPanics(t, func() {
ok = testing.RunTests(allTestsFilter, panickingTests)
})
assert.False(t, ok)
}
// This suite is intended to store values to make sure that only // This suite is intended to store values to make sure that only
// testing-suite-related methods are run. It's also a fully // testing-suite-related methods are run. It's also a fully
// functional example of a testing suite, using setup/teardown methods // functional example of a testing suite, using setup/teardown methods
@ -59,6 +152,7 @@ type SuiteTester struct {
TearDownTestRunCount int TearDownTestRunCount int
TestOneRunCount int TestOneRunCount int
TestTwoRunCount int TestTwoRunCount int
TestSubtestRunCount int
NonTestMethodRunCount int NonTestMethodRunCount int
SuiteNameBefore []string SuiteNameBefore []string
@ -153,6 +247,27 @@ func (suite *SuiteTester) NonTestMethod() {
suite.NonTestMethodRunCount++ suite.NonTestMethodRunCount++
} }
func (suite *SuiteTester) TestSubtest() {
suite.TestSubtestRunCount++
for _, t := range []struct {
testName string
}{
{"first"},
{"second"},
} {
suiteT := suite.T()
suite.Run(t.testName, func() {
// We should get a different *testing.T for subtests, so that
// go test recognizes them as proper subtests for output formatting
// and running individual subtests
subTestT := suite.T()
suite.NotEqual(subTestT, suiteT)
})
suite.Equal(suiteT, suite.T())
}
}
// TestRunSuite will be run by the 'go test' command, so within it, we // TestRunSuite will be run by the 'go test' command, so within it, we
// can run our suite using the Run(*testing.T, TestingSuite) function. // can run our suite using the Run(*testing.T, TestingSuite) function.
func TestRunSuite(t *testing.T) { func TestRunSuite(t *testing.T) {
@ -168,18 +283,20 @@ func TestRunSuite(t *testing.T) {
assert.Equal(t, suiteTester.SetupSuiteRunCount, 1) assert.Equal(t, suiteTester.SetupSuiteRunCount, 1)
assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1) assert.Equal(t, suiteTester.TearDownSuiteRunCount, 1)
assert.Equal(t, len(suiteTester.SuiteNameAfter), 3) assert.Equal(t, len(suiteTester.SuiteNameAfter), 4)
assert.Equal(t, len(suiteTester.SuiteNameBefore), 3) assert.Equal(t, len(suiteTester.SuiteNameBefore), 4)
assert.Equal(t, len(suiteTester.TestNameAfter), 3) assert.Equal(t, len(suiteTester.TestNameAfter), 4)
assert.Equal(t, len(suiteTester.TestNameBefore), 3) assert.Equal(t, len(suiteTester.TestNameBefore), 4)
assert.Contains(t, suiteTester.TestNameAfter, "TestOne") assert.Contains(t, suiteTester.TestNameAfter, "TestOne")
assert.Contains(t, suiteTester.TestNameAfter, "TestTwo") assert.Contains(t, suiteTester.TestNameAfter, "TestTwo")
assert.Contains(t, suiteTester.TestNameAfter, "TestSkip") assert.Contains(t, suiteTester.TestNameAfter, "TestSkip")
assert.Contains(t, suiteTester.TestNameAfter, "TestSubtest")
assert.Contains(t, suiteTester.TestNameBefore, "TestOne") assert.Contains(t, suiteTester.TestNameBefore, "TestOne")
assert.Contains(t, suiteTester.TestNameBefore, "TestTwo") assert.Contains(t, suiteTester.TestNameBefore, "TestTwo")
assert.Contains(t, suiteTester.TestNameBefore, "TestSkip") assert.Contains(t, suiteTester.TestNameBefore, "TestSkip")
assert.Contains(t, suiteTester.TestNameBefore, "TestSubtest")
for _, suiteName := range suiteTester.SuiteNameAfter { for _, suiteName := range suiteTester.SuiteNameAfter {
assert.Equal(t, "SuiteTester", suiteName) assert.Equal(t, "SuiteTester", suiteName)
@ -197,15 +314,16 @@ func TestRunSuite(t *testing.T) {
assert.False(t, when.IsZero()) assert.False(t, when.IsZero())
} }
// There are three test methods (TestOne, TestTwo, and TestSkip), so // There are four test methods (TestOne, TestTwo, TestSkip, and TestSubtest), so
// the SetupTest and TearDownTest methods (which should be run once for // the SetupTest and TearDownTest methods (which should be run once for
// each test) should have been run three times. // each test) should have been run four times.
assert.Equal(t, suiteTester.SetupTestRunCount, 3) assert.Equal(t, suiteTester.SetupTestRunCount, 4)
assert.Equal(t, suiteTester.TearDownTestRunCount, 3) assert.Equal(t, suiteTester.TearDownTestRunCount, 4)
// Each test should have been run once. // Each test should have been run once.
assert.Equal(t, suiteTester.TestOneRunCount, 1) assert.Equal(t, suiteTester.TestOneRunCount, 1)
assert.Equal(t, suiteTester.TestTwoRunCount, 1) assert.Equal(t, suiteTester.TestTwoRunCount, 1)
assert.Equal(t, suiteTester.TestSubtestRunCount, 1)
// Methods that don't match the test method identifier shouldn't // Methods that don't match the test method identifier shouldn't
// have been run at all. // have been run at all.

3
zk.go
View file

@ -146,7 +146,8 @@ func LeaderFromZKOpts(options ...ZKOpt) (string, error) {
// This should never be encountered as it would indicate Aurora // This should never be encountered as it would indicate Aurora
// writing bad info into Zookeeper but is kept here as a safety net. // writing bad info into Zookeeper but is kept here as a safety net.
if len(serviceInst.AdditionalEndpoints) > 1 { if len(serviceInst.AdditionalEndpoints) > 1 {
return false, NewTemporaryError(errors.New("ambiguous endpoints in json blob, Aurora wrote bad info to ZK")) return false,
NewTemporaryError(errors.New("ambiguous endpoints in json blob, Aurora wrote bad info to ZK"))
} }
var scheme, host, port string var scheme, host, port string