From 23535ae8d309e8684ce15e1965ab7fbe24aa75e0 Mon Sep 17 00:00:00 2001 From: Neko Ayaka Date: Mon, 27 Nov 2023 15:27:06 +0800 Subject: [PATCH] feat: added new parameters for parameterized query 1. added new `whereSQLStmt` for parameterized query statement 2. added new `whereSQLParams` for parameterized query parameters 3. added new `whereSQLJSONParams` for parameterized query parameters in JSON format with base64 encoding Signed-off-by: Neko Ayaka (cherry picked from commit de9a57f727964b7682b1eb3b541196569339df82) Signed-off-by: Iceber Gu --- pkg/storage/internalstorage/storage_test.go | 56 +- pkg/storage/internalstorage/util.go | 174 +- pkg/storage/internalstorage/util_test.go | 1120 +++++++++- .../stretchr/testify/require/doc.go | 28 + .../testify/require/forward_requirements.go | 16 + .../stretchr/testify/require/require.go | 1935 +++++++++++++++++ .../stretchr/testify/require/require.go.tmpl | 6 + .../testify/require/require_forward.go | 1515 +++++++++++++ .../testify/require/require_forward.go.tmpl | 5 + .../stretchr/testify/require/requirements.go | 29 + vendor/modules.txt | 1 + 11 files changed, 4858 insertions(+), 27 deletions(-) create mode 100644 vendor/github.com/stretchr/testify/require/doc.go create mode 100644 vendor/github.com/stretchr/testify/require/forward_requirements.go create mode 100644 vendor/github.com/stretchr/testify/require/require.go create mode 100644 vendor/github.com/stretchr/testify/require/require.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go create mode 100644 vendor/github.com/stretchr/testify/require/require_forward.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/require/requirements.go diff --git a/pkg/storage/internalstorage/storage_test.go b/pkg/storage/internalstorage/storage_test.go index 023952a4a..7ba1933f9 100644 --- a/pkg/storage/internalstorage/storage_test.go +++ b/pkg/storage/internalstorage/storage_test.go @@ -2,6 +2,8 @@ package internalstorage import ( "fmt" + "os" + "testing" "github.com/DATA-DOG/go-sqlmock" gmysql "gorm.io/driver/mysql" @@ -10,34 +12,64 @@ import ( ) var ( - postgresDB *gorm.DB + postgresDB *gorm.DB + postgresDBMock sqlmock.Sqlmock mysqlVersions = []string{"8.0.27", "5.7.22"} mysqlDBs = make(map[string]*gorm.DB, 2) + mysqlDBMocks = make(map[string]sqlmock.Sqlmock, 2) ) -func init() { - db, _, err := sqlmock.New() +func newMockedPostgresDB() (*gorm.DB, sqlmock.Sqlmock, error) { + mockedDB, mock, err := sqlmock.New() if err != nil { - panic(fmt.Sprintf("sqlmock.New() failed: %v", err)) + return nil, nil, fmt.Errorf("sqlmock.New() failed: %w", err) } - postgresDB, err = gorm.Open(gpostgres.New(gpostgres.Config{Conn: db})) + gormDB, err := gorm.Open(gpostgres.New(gpostgres.Config{Conn: mockedDB})) if err != nil { - panic(fmt.Sprintf("init postgresDB failed: %v", err)) + return nil, nil, fmt.Errorf("init postgresDB failed: %w", err) } - for _, version := range mysqlVersions { - db, mock, err := sqlmock.New() + return gormDB, mock, nil +} + +func newMockedMySQLDB(version string) (*gorm.DB, sqlmock.Sqlmock, error) { + mockedDB, mock, err := sqlmock.New() + if err != nil { + return nil, nil, fmt.Errorf("sqlmock.New() failed: %w", err) + } + + mock.ExpectQuery("SELECT VERSION()").WillReturnRows(sqlmock.NewRows([]string{"VERSION()"}).AddRow(version)) + + mysqlDB, err := gorm.Open(gmysql.New(gmysql.Config{Conn: mockedDB})) + if err != nil { + return nil, nil, fmt.Errorf("init mysqlDB(%s) failed: %w", version, err) + } + + return mysqlDB, mock, nil +} + +func TestMain(m *testing.M) { + { + mockedDB, mock, err := newMockedPostgresDB() if err != nil { - panic(fmt.Sprintf("sqlmock.New() failed: %v", err)) + panic(err) } - mock.ExpectQuery("SELECT VERSION()").WillReturnRows(sqlmock.NewRows([]string{"VERSION()"}).AddRow(version)) - mysqlDB, err := gorm.Open(gmysql.New(gmysql.Config{Conn: db})) + postgresDB = mockedDB + postgresDBMock = mock + } + + for _, version := range mysqlVersions { + mysqlDB, mock, err := newMockedMySQLDB(version) if err != nil { - panic(fmt.Sprintf("init mysqlDB(%s) failed: %v", version, err)) + panic(err) } + mysqlDBs[version] = mysqlDB + mysqlDBMocks[version] = mock } + + os.Exit(m.Run()) } diff --git a/pkg/storage/internalstorage/util.go b/pkg/storage/internalstorage/util.go index 77cfbb049..6da724225 100644 --- a/pkg/storage/internalstorage/util.go +++ b/pkg/storage/internalstorage/util.go @@ -1,7 +1,9 @@ package internalstorage import ( + "encoding/base64" "fmt" + "net/url" "strconv" "strings" @@ -10,6 +12,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/util/json" "k8s.io/apimachinery/pkg/util/validation/field" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -19,9 +22,165 @@ import ( const ( SearchLabelFuzzyName = "internalstorage.clusterpedia.io/fuzzy-name" + // Raw query URLQueryWhereSQL = "whereSQL" + // Parameterized query + URLQueryFieldWhereSQLStatement = "whereSQLStatement" + URLQueryFieldWhereSQLParam = "whereSQLParam" + URLQueryFieldWhereSQLJSONParams = "whereSQLJSONParams" ) +type URLQueryWhereSQLParams struct { + // Raw query + WhereSQL string + // Parameterized query + WhereSQLStatement string + WhereSQLParams []string + WhereSQLJSONParams []any +} + +// NewURLQueryWhereSQLParamsFromURLValues resolves parameters from passed in url.Values. +// A k8s.io/apimachinery/pkg/api/errors.StatusError will be returned if decoding or unmarshalling failed +// only when the value of "whereSQLJSONParams" is present. +// +// It recognizes the following query fields for parameters: +// +// "whereSQL" +// "whereSQLStatement" +// "whereSQLParam" +// "whereSQLJSONParams" +func NewURLQueryWhereSQLParamsFromURLValues(urlQuery url.Values) (URLQueryWhereSQLParams, error) { + var params URLQueryWhereSQLParams + + whereClause, ok := urlQuery[URLQueryWhereSQL] + if ok && len(whereClause) > 0 { + params.WhereSQL = whereClause[0] + } + + whereClauseStatement, ok := urlQuery[URLQueryFieldWhereSQLStatement] + if ok && len(whereClauseStatement) > 0 { + params.WhereSQLStatement = whereClauseStatement[0] + } + + whereClauseParams, ok := urlQuery[URLQueryFieldWhereSQLParam] + if ok { + params.WhereSQLParams = whereClauseParams + } + + whereClauseJSONParams, ok := urlQuery[URLQueryFieldWhereSQLJSONParams] + if ok && len(whereClauseJSONParams) > 0 { + decodedBytesContent, err := base64.StdEncoding.DecodeString(whereClauseJSONParams[0]) + if err != nil { + return URLQueryWhereSQLParams{}, apierrors.NewInvalid( + schema.GroupKind{Group: internal.GroupName, Kind: "ListOptions"}, + "urlQuery", + field.ErrorList{ + field.Invalid( + field.NewPath(URLQueryFieldWhereSQLJSONParams), + whereClauseJSONParams[0], + fmt.Sprintf("failed to decode base64 string: %v", err), + ), + }, + ) + } + + params.WhereSQLJSONParams = make([]any, 0) + err = json.Unmarshal(decodedBytesContent, ¶ms.WhereSQLJSONParams) + if err != nil { + return URLQueryWhereSQLParams{}, apierrors.NewInvalid( + schema.GroupKind{Group: internal.GroupName, Kind: "ListOptions"}, + "urlQuery", + field.ErrorList{ + field.Invalid( + field.NewPath(URLQueryFieldWhereSQLJSONParams), + whereClauseJSONParams[0], + fmt.Sprintf("failed to unmarshal decoded base64 string to JSON array: %v", err), + ), + }, + ) + } + } + + if (len(params.WhereSQLParams) > 0 || len(params.WhereSQLJSONParams) > 0) && params.WhereSQLStatement == "" { + return URLQueryWhereSQLParams{}, apierrors.NewInvalid( + schema.GroupKind{Group: internal.GroupName, Kind: "ListOptions"}, + "urlQuery", + field.ErrorList{ + field.Invalid( + field.NewPath(URLQueryFieldWhereSQLStatement), + whereClauseStatement, + fmt.Sprintf("required when either %s or %s was provided", URLQueryFieldWhereSQLParam, URLQueryFieldWhereSQLJSONParams), + ), + }, + ) + } + + return params, nil +} + +func applyListOptionsURLQueryParameterizedQueryToWhereClause(query *gorm.DB, params URLQueryWhereSQLParams) *gorm.DB { + if params.WhereSQLStatement == "" { + return query + } + + // If a string of numbers is passed in from SQL, the query will be taken as ID by default. + // If the SQL contains English letter, it will be passed in as column. + + if len(params.WhereSQLJSONParams) > 0 { + return query.Where(params.WhereSQLStatement, params.WhereSQLJSONParams...) + } + if len(params.WhereSQLParams) > 0 { + anyParameters := make([]any, len(params.WhereSQLParams)) + + for i := range params.WhereSQLParams { + anyParameters[i] = params.WhereSQLParams[i] + } + + return query.Where(params.WhereSQLStatement, anyParameters...) + } + + return query.Where(params.WhereSQLStatement) +} + +// applyListOptionsURLQueryToWhereClause applies the where sql related parameters from url query to the where clause of the query. +// +// By design, both the parameters of whereSQLStatement and whereSQL will be accepted and be part of the query in order when +// AllowRawSQLQuery feature gate is enabled, and only whereSQLStatement will be accepted and be part of the query when +// AllowParameterizedSQLQuery feature gate is enabled. +func applyListOptionsURLQueryToWhereClause(query *gorm.DB, urlValues url.Values, allowRawSQLQueryEnabled bool, allowParameterizedSQLQueryEnabled bool) (*gorm.DB, error) { + if !allowRawSQLQueryEnabled && !allowParameterizedSQLQueryEnabled { + return query, nil + } + + urlQueryParams, err := NewURLQueryWhereSQLParamsFromURLValues(urlValues) + if err != nil { + return query, err + } + + if allowRawSQLQueryEnabled { + // use parameterized query first if statement was provided + // + // since users will need to migrate from caller (business) side first and make their transition + // to the newly added feature gate AllowParameterizedSQLQuery step by step, therefore a compatible + // implementation is required here to allow the migration and transition from caller (business) side + // while the existing feature gates that enabled for Clusterpedia deployment can be left as untouched + // and keep working as expected. + if urlQueryParams.WhereSQLStatement != "" { + return applyListOptionsURLQueryParameterizedQueryToWhereClause(query, urlQueryParams), nil + } + // otherwise, fallbacks to raw query + if urlQueryParams.WhereSQL != "" { + return query.Where(urlQueryParams.WhereSQL), nil + } + } + + if allowParameterizedSQLQueryEnabled && urlQueryParams.WhereSQLStatement != "" { + return applyListOptionsURLQueryParameterizedQueryToWhereClause(query, urlQueryParams), nil + } + + return query, nil +} + func applyListOptionsToQuery(query *gorm.DB, opts *internal.ListOptions, applyFn func(query *gorm.DB, opts *internal.ListOptions) (*gorm.DB, error)) (int64, *int64, *gorm.DB, error) { switch len(opts.ClusterNames) { case 0: @@ -55,13 +214,14 @@ func applyListOptionsToQuery(query *gorm.DB, opts *internal.ListOptions, applyFn query = query.Where("created_at < ?", opts.Before.Time.UTC()) } - if utilfeature.DefaultMutableFeatureGate.Enabled(AllowRawSQLQuery) { - if len(opts.URLQuery[URLQueryWhereSQL]) > 0 { - // TODO: prevent SQL injection. - // If a string of numbers is passed in from SQL, the query will be taken as ID by default. - // If the SQL contains English letter, it will be passed in as column. - query = query.Where(opts.URLQuery[URLQueryWhereSQL][0]) - } + query, err := applyListOptionsURLQueryToWhereClause( + query, + opts.URLQuery, + utilfeature.DefaultMutableFeatureGate.Enabled(AllowRawSQLQuery), + false, + ) + if err != nil { + return 0, nil, nil, err } if opts.LabelSelector != nil { diff --git a/pkg/storage/internalstorage/util_test.go b/pkg/storage/internalstorage/util_test.go index a45634111..29cdf04ac 100644 --- a/pkg/storage/internalstorage/util_test.go +++ b/pkg/storage/internalstorage/util_test.go @@ -1,19 +1,146 @@ package internalstorage import ( + "database/sql/driver" + "encoding/base64" + "encoding/json" "fmt" + "net/url" "testing" "time" + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "gorm.io/gorm" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" kubefields "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/util/validation/field" internal "github.com/clusterpedia-io/api/clusterpedia" "github.com/clusterpedia-io/api/clusterpedia/fields" ) +func toFindQuery[P any](db *gorm.DB, options P, applyFn func(*gorm.DB, P) (*gorm.DB, error), dryRun bool) (*gorm.DB, error) { + query := db.Session(&gorm.Session{DryRun: dryRun}).Model(&Resource{}) + query, err := applyFn(query, options) + if err != nil { + return nil, err + } + + return query.Find(&Resource{}), nil +} + +// replace db.ToSQL +func toSQL[P any](db *gorm.DB, options P, applyFn func(*gorm.DB, P) (*gorm.DB, error)) (string, error) { + query, err := toFindQuery(db, options, applyFn, true) + if err != nil { + return "", err + } + + return db.Dialector.Explain(query.Statement.SQL.String(), query.Statement.Vars...), nil +} + +func assertSQL[P any](t *testing.T, db *gorm.DB, options P, applyFn func(*gorm.DB, P) (*gorm.DB, error), expectedQuery string, expectedError error) { + sql, err := toSQL(db, options, applyFn) + if expectedError == nil { + require.NoError(t, err) + assert.Equal(t, expectedQuery, sql) + } else { + require.Error(t, err) + assert.Equal(t, expectedError, err) + } +} + +func toUnexplainedSQL[P any](db *gorm.DB, options P, applyFn func(*gorm.DB, P) (*gorm.DB, error)) (string, error) { + query, err := toFindQuery(db, options, applyFn, true) + if err != nil { + return "", err + } + + return query.Statement.SQL.String(), nil +} + +func assertUnexplainedSQL[P any](t *testing.T, db *gorm.DB, options P, applyFn func(*gorm.DB, P) (*gorm.DB, error), expectedQuery string, expectedError error) { + sql, err := toUnexplainedSQL(db, options, applyFn) + if expectedError == nil { + require.NoError(t, err) + assert.Equal(t, expectedQuery, sql) + } else { + require.Error(t, err) + assert.Equal(t, expectedError, err) + } +} + +func assertDatabaseExecutedSQL[P any]( + t *testing.T, + db *gorm.DB, + mock sqlmock.Sqlmock, + options P, + applyFn func(*gorm.DB, P) (*gorm.DB, error), + expectedQuery string, + args []driver.Value, + expectedError error, +) { + if expectedError == nil { + mock. + ExpectQuery(expectedQuery). + WithArgs(args...). + WillReturnRows(sqlmock.NewRows([]string{"id", "test_column", "test_column2", "test_column3"})) + } + + query, err := toFindQuery( + db, + options, + applyFn, + false, + ) + if expectedError == nil { + require.NoError(t, err) + require.NotNil(t, query) + } else { + require.Error(t, err) + assert.Equal(t, expectedError, err) + } + + err = mock.ExpectationsWereMet() + assert.NoError(t, err) +} + +func assertPostgresDatabaseExecutedSQL[P any]( + t *testing.T, + options P, + applyFn func(*gorm.DB, P) (*gorm.DB, error), + expectedQuery string, + args []driver.Value, + expectedError error, +) { + db, mock, err := newMockedPostgresDB() + require.NoError(t, err) + require.NotNil(t, db) + + assertDatabaseExecutedSQL(t, db, mock, options, applyFn, expectedQuery, args, expectedError) +} + +func assertMySQLDatabaseExecutedSQL[P any]( + t *testing.T, + version string, + options P, + applyFn func(*gorm.DB, P) (*gorm.DB, error), + expectedQuery string, + args []driver.Value, + expectedError error, +) { + db, mock, err := newMockedMySQLDB(version) + require.NoError(t, err) + require.NotNil(t, db) + + assertDatabaseExecutedSQL(t, db, mock, options, applyFn, expectedQuery, args, expectedError) +} + type expected struct { postgres string mysql string @@ -531,16 +658,993 @@ func TestApplyListOptionsToQuery_Page(t *testing.T) { } } -// replace db.ToSQL -func toSQL(db *gorm.DB, options *internal.ListOptions, applyFn func(*gorm.DB, *internal.ListOptions) (*gorm.DB, error)) (string, error) { - query := db.Session(&gorm.Session{DryRun: true}).Model(&Resource{}) - query, err := applyFn(query, options) - if err != nil { - return "", err +func newURLQueryFieldWhereSQLJSONParamsBase64DecodingError() (string, *apierrors.StatusError) { + corruptedBase64Payload := "A===" + _, corruptedBase64PayloadError := base64.StdEncoding.DecodeString(corruptedBase64Payload) + + return corruptedBase64Payload, apierrors.NewInvalid( + schema.GroupKind{Group: internal.GroupName, Kind: "ListOptions"}, + "urlQuery", + field.ErrorList{ + field.Invalid( + field.NewPath(URLQueryFieldWhereSQLJSONParams), + corruptedBase64Payload, + fmt.Sprintf("failed to decode base64 string: %v", corruptedBase64PayloadError), + ), + }, + ) +} + +func newURLQueryFieldWhereSQLJSONParamsUnmarshalError(originalJSONPayloadContent string) (string, *apierrors.StatusError) { + base64EncodedContent := base64.StdEncoding.EncodeToString([]byte(originalJSONPayloadContent)) + var unmarshalDest []any + unmarshalError := json.Unmarshal([]byte(originalJSONPayloadContent), &unmarshalDest) + + return base64EncodedContent, apierrors.NewInvalid( + schema.GroupKind{Group: internal.GroupName, Kind: "ListOptions"}, + "urlQuery", + field.ErrorList{ + field.Invalid( + field.NewPath(URLQueryFieldWhereSQLJSONParams), + base64EncodedContent, + fmt.Sprintf("failed to unmarshal decoded base64 string to JSON array: %v", unmarshalError), + ), + }, + ) +} + +func newURLQueryFieldWhereSQLStatementRequiredError() *apierrors.StatusError { + var emptyWhereSQLStmt []string + + return apierrors.NewInvalid( + schema.GroupKind{Group: internal.GroupName, Kind: "ListOptions"}, + "urlQuery", + field.ErrorList{ + field.Invalid( + field.NewPath(URLQueryFieldWhereSQLStatement), + emptyWhereSQLStmt, + fmt.Sprintf("required when either %s or %s was provided", URLQueryFieldWhereSQLParam, URLQueryFieldWhereSQLJSONParams), + ), + }, + ) +} + +func TestNewURLQueryWhereSQLParamsFromURLValues(t *testing.T) { + type testCase struct { + name string + urlValues url.Values + + expectedAPIError *apierrors.StatusError + expectedAPIErrorString string + + expectedWhereSQL string + expectedWhereSQLStatement string + expectedWhereSQLParams []string + expectedWhereSQLJSONParams []any + } + + base64DecodingErrorPayload, base64DecodingError := newURLQueryFieldWhereSQLJSONParamsBase64DecodingError() + jsonUnmarshalErrorInvalidJSONErrorPayload, jsonUnmarshalErrorInvalidJSONError := newURLQueryFieldWhereSQLJSONParamsUnmarshalError("invalid-json") + jsonUnmarshalErrorNonJSONArrayErrorPayload, jsonUnmarshalErrorNonJSONArrayError := newURLQueryFieldWhereSQLJSONParamsUnmarshalError(`{"key1": "value1", "key2": "value2"}`) + + validJSONPayload := `["value1", "value2"]` + encodedBase64ValidJSONPayload := base64.StdEncoding.EncodeToString([]byte(validJSONPayload)) + validJSONPayloadUnmarshal := []any{"value1", "value2"} + + urlQueryFieldWhereSQLStatementRequiredError := newURLQueryFieldWhereSQLStatementRequiredError() + + testCases := []testCase{ + { + name: "WhereSQLWithoutAnyParams", + urlValues: url.Values{ + URLQueryWhereSQL: []string{"test_column = ?"}, + }, + expectedWhereSQL: "test_column = ?", + }, + { + name: "WhereSQLStatementWithoutAnyParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + }, + expectedWhereSQLStatement: "test_column = ?", + }, + { + name: "WhereSQLStatementWithWhereSQLParam", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1"}, + }, + expectedWhereSQLStatement: "test_column = ?", + expectedWhereSQLParams: []string{"value1"}, + }, + { + name: "WhereSQLStatementWithMultipleWhereSQLParam", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ? AND test_column2 = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1", "value2"}, + }, + expectedWhereSQLStatement: "test_column = ? AND test_column2 = ?", + expectedWhereSQLParams: []string{"value1", "value2"}, + }, + { + name: "WhereSQLStatementWithWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLJSONParams: []string{encodedBase64ValidJSONPayload}, + }, + expectedWhereSQLStatement: "test_column = ?", + expectedWhereSQLJSONParams: validJSONPayloadUnmarshal, + }, + { + name: "WhereSQLStatementWithMultipleWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLJSONParams: []string{encodedBase64ValidJSONPayload, encodedBase64ValidJSONPayload}, + }, + expectedWhereSQLStatement: "test_column = ?", + expectedWhereSQLJSONParams: validJSONPayloadUnmarshal, + }, + { + name: "WhereSQLStatementWithBothWhereSQLParamAndWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1"}, + URLQueryFieldWhereSQLJSONParams: []string{encodedBase64ValidJSONPayload}, + }, + expectedWhereSQLStatement: "test_column = ?", + expectedWhereSQLParams: []string{"value1"}, + expectedWhereSQLJSONParams: validJSONPayloadUnmarshal, + }, + { + name: "WhereSQLStatementWithBothMultipleWhereSQLParamAndWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ? AND test_column2 = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1", "value2"}, + URLQueryFieldWhereSQLJSONParams: []string{encodedBase64ValidJSONPayload}, + }, + expectedWhereSQLStatement: "test_column = ? AND test_column2 = ?", + expectedWhereSQLParams: []string{"value1", "value2"}, + expectedWhereSQLJSONParams: validJSONPayloadUnmarshal, + }, + { + name: "CorruptedBase64PayloadValueOfWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLJSONParams: []string{base64DecodingErrorPayload}, + }, + expectedAPIError: base64DecodingError, + expectedAPIErrorString: base64DecodingError.Error(), + }, + { + name: "InvalidBase64EncodedJSONPayloadValueOfWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLJSONParams: []string{jsonUnmarshalErrorInvalidJSONErrorPayload}, + }, + expectedAPIError: jsonUnmarshalErrorInvalidJSONError, + expectedAPIErrorString: jsonUnmarshalErrorInvalidJSONError.Error(), + }, + { + name: "NonJSONArrayBase64EncodedJSONPayloadValueOfWhereSQLJSONParams", + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLJSONParams: []string{jsonUnmarshalErrorNonJSONArrayErrorPayload}, + }, + expectedAPIError: jsonUnmarshalErrorNonJSONArrayError, + expectedAPIErrorString: jsonUnmarshalErrorNonJSONArrayError.Error(), + }, + { + name: "WhereSQLParamsWithoutWhereSQLStatement", + urlValues: url.Values{ + URLQueryFieldWhereSQLParam: []string{"value1"}, + }, + expectedAPIError: urlQueryFieldWhereSQLStatementRequiredError, + expectedAPIErrorString: urlQueryFieldWhereSQLStatementRequiredError.Error(), + }, + { + name: "WhereSQLJSONParamsWithoutWhereSQLStatement", + urlValues: url.Values{ + URLQueryFieldWhereSQLJSONParams: []string{encodedBase64ValidJSONPayload}, + }, + expectedAPIError: urlQueryFieldWhereSQLStatementRequiredError, + expectedAPIErrorString: urlQueryFieldWhereSQLStatementRequiredError.Error(), + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + params, err := NewURLQueryWhereSQLParamsFromURLValues(tc.urlValues) + if tc.expectedAPIError == nil { + require.NoError(t, err) + } else { + require.Error(t, err) + + apiError, ok := err.(*apierrors.StatusError) + require.True(t, ok) + require.NotNil(t, apiError) + + assert.Equal(t, tc.expectedAPIError, apiError) + assert.EqualError(t, err, tc.expectedAPIErrorString) + } + + assert.Equal(t, tc.expectedWhereSQL, params.WhereSQL) + assert.Equal(t, tc.expectedWhereSQLStatement, params.WhereSQLStatement) + assert.Equal(t, tc.expectedWhereSQLParams, params.WhereSQLParams) + assert.Equal(t, tc.expectedWhereSQLJSONParams, params.WhereSQLJSONParams) + }) + } +} + +type testSQLQueriesAssertionTestCase struct { + ignorePostgres bool + postgresRawQuery string + postgresUnexplainedRawQuery string + postgresSqlmockDBExecutedQuery string + postgresSqlmockDBExecutedArgs []driver.Value + + ignoreMySQL bool + mysqlRawQuery string + mysqlUnexplainedRawQuery string + mysqlSqlmockDBExecutedQuery string + mysqlSqlmockDBExecutedArgs []driver.Value + + expectedError error +} + +func testSQLQueriesAssertion[P any](t *testing.T, params P, testCase testSQLQueriesAssertionTestCase, applyFn func(*gorm.DB, P) (*gorm.DB, error)) { + t.Run("Postgres", func(t *testing.T) { + t.Run("RawQuery", func(t *testing.T) { + if testCase.ignorePostgres { + t.Skip("skipped due to explicit ignoring flag") + return + } + + assertSQL(t, postgresDB, params, applyFn, testCase.postgresRawQuery, testCase.expectedError) + }) + + t.Run("UnexplainedRawQuery", func(t *testing.T) { + if testCase.ignorePostgres { + t.Skip("skipped due to explicit ignoring flag") + return + } + + assertUnexplainedSQL(t, postgresDB, params, applyFn, testCase.postgresUnexplainedRawQuery, testCase.expectedError) + }) + + t.Run("DBExecutedQuery", func(t *testing.T) { + if testCase.ignorePostgres { + t.Skip("skipped due to explicit ignoring flag") + return + } + + assertPostgresDatabaseExecutedSQL(t, params, applyFn, testCase.postgresSqlmockDBExecutedQuery, testCase.postgresSqlmockDBExecutedArgs, testCase.expectedError) + }) + }) + + for version, mysqlDB := range mysqlDBs { + version := version + mysqlDB := mysqlDB + + t.Run(fmt.Sprintf("MySQL%s", version), func(t *testing.T) { + t.Run("RawQuery", func(t *testing.T) { + if testCase.ignoreMySQL { + t.Skip("skipped due to explicit ignoring flag") + return + } + + assertSQL(t, mysqlDB, params, applyFn, testCase.mysqlRawQuery, testCase.expectedError) + }) + + t.Run("UnexplainedRawQuery", func(t *testing.T) { + if testCase.ignoreMySQL { + t.Skip("skipped due to explicit ignoring flag") + return + } + + assertUnexplainedSQL(t, mysqlDB, params, applyFn, testCase.mysqlUnexplainedRawQuery, testCase.expectedError) + }) + + t.Run("DBExecutedQuery", func(t *testing.T) { + if testCase.ignoreMySQL { + t.Skip("skipped due to explicit ignoring flag") + return + } + + assertMySQLDatabaseExecutedSQL(t, version, params, applyFn, testCase.mysqlSqlmockDBExecutedQuery, testCase.mysqlSqlmockDBExecutedArgs, testCase.expectedError) + }) + }) } +} + +type applyListOptionsURLQueryParameterizedQueryToWhereClauseTestCase struct { + testSQLQueriesAssertionTestCase + + name string + + whereSQLParams URLQueryWhereSQLParams + whereSQLJSONParams URLQueryWhereSQLParams +} + +func TestApplyListOptionsURLQueryParameterizedQueryToWhereClause(t *testing.T) { + commonTestCases := []applyListOptionsURLQueryParameterizedQueryToWhereClauseTestCase{ + { + name: "WithoutWhereSQLStatement", + + whereSQLParams: URLQueryWhereSQLParams{}, + whereSQLJSONParams: URLQueryWhereSQLParams{}, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\"", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\"", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\"", + + mysqlRawQuery: "SELECT * FROM `resources`", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources`", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources`", + }, + }, + { + name: "WithoutAnyParameters/SingleWhereClause", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = value1", + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = value1", + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1", + }, + }, + { + name: "WithoutAnyParameters/MultipleWhereClauses", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = value1 AND created_at > value2", + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = value1 AND created_at > value2", + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1 AND created_at > value2", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1 AND created_at > value2", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1 AND created_at > value2", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1 AND created_at > value2", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1 AND created_at > value2", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1 AND created_at > value2", + }, + }, + { + name: "WithoutAnyParameters/ExplicitPotentialSQLInjectionPayload", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = value1 OR 1=1", + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = value1 OR 1=1", + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1 OR 1=1", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1 OR 1=1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1 OR 1=1", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1 OR 1=1", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1 OR 1=1", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1 OR 1=1", + }, + }, + { + name: "WithParameters/SingleParameter", + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLParams: []string{"value1"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLJSONParams: []any{"value1"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = 'value1'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = 'value1'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1"}, + }, + }, + { + name: "WithParameters/MultipleParameters", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = ?", + WhereSQLParams: []string{"value1", "value2"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = ?", + WhereSQLJSONParams: []any{"value1", "value2"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = 'value1' AND test_column2 = 'value2'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1 AND test_column2 = $2", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1 AND test_column2 = \\$2", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1", "value2"}, - stmt := query.Find(interface{}(nil)).Statement - return db.Dialector.Explain(stmt.SQL.String(), stmt.Vars...), nil + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = 'value1' AND test_column2 = 'value2'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ? AND test_column2 = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\? AND test_column2 = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1", "value2"}, + }, + }, + { + name: "WithParameters/Mismatched", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = ?", + WhereSQLParams: []string{"value1"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = ?", + WhereSQLJSONParams: []any{"value1"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = 'value1' AND test_column2 = ?", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1 AND test_column2 = ?", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1 AND test_column2 = \\?", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = 'value1' AND test_column2 = ?", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ? AND test_column2 = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\? AND test_column2 = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1"}, + }, + }, + + // Injection test cases + // This is the commonly used case where OR 1=1 will make the where clause always true if not well escaped. + { + name: "DefendSQLInjectionPayload/AlwaysTrue", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLParams: []string{" OR ('1' = '1"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLJSONParams: []any{" OR ('1' = '1"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = ' OR (\\'1\\' = \\'1'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{" OR ('1' = '1"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = ' OR (\\'1\\' = \\'1'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{" OR ('1' = '1"}, + }, + }, + // Assume that there is a 'test_column2 = true' where clause after the possible injected where clause + // appending -- to the end of the where clause will comment out the rest of the query if not well escaped. + { + name: "DefendSQLInjectionPayload/Comment", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = true", + WhereSQLParams: []string{" OR ('1' = '1'); --"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = true", + WhereSQLJSONParams: []any{" OR ('1' = '1'); --"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = ' OR (\\'1\\' = \\'1\\'); --' AND test_column2 = true", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1 AND test_column2 = true", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{" OR ('1' = '1'); --"}, + + ignoreMySQL: true, + }, + }, + // Same as above but for MySQL + { + name: "DefendSQLInjectionPayload/Comment", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = true", + WhereSQLParams: []string{" OR ('1' = '1'); #"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ? AND test_column2 = true", + WhereSQLJSONParams: []any{" OR ('1' = '1'); #"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + ignorePostgres: true, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = ' OR (\\'1\\' = \\'1\\'); #' AND test_column2 = true", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ? AND test_column2 = true", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\? AND test_column2 = true", + mysqlSqlmockDBExecutedArgs: []driver.Value{" OR ('1' = '1'); #"}, + }, + }, + // This is a bit complicated. Assume that there are three columns in the table, test_column, test_column2 and test_column3. + // Attack could use + // UNION SELECT NULL-- + // UNION SELECT NULL,NULL–- + // UNION SELECT NULL,NULL-- + // UNION SELECT NULL,NULL,NULL,NULL-- + // to find out the number of columns in the table. And then use + // UNION SELECT 'a' ,NULL,NULL,NULL-- + // UNION SELECT NULL,'a',NULL,NULL-- + // UNION SELECT NULL,NULL,'a',NULL-- + // UNION SELECT NULL,NULL,NULL,'a'-- + // to find out the types of the columns in the table. + // Finally, attacker could use + // UNION SELECT other_column1, other_column2, other_column3 FROM other_table + // to extract data from other tables. + { + name: "DefendSQLInjectionPayload/UNIONBased/ColumnCountDetermination", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLParams: []string{" UNION SELECT NULL,NULL,NULL;--"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLJSONParams: []any{" UNION SELECT NULL,NULL,NULL;--"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = ' UNION SELECT NULL,NULL,NULL;--'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{" UNION SELECT NULL,NULL,NULL;--"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = ' UNION SELECT NULL,NULL,NULL;--'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{" UNION SELECT NULL,NULL,NULL;--"}, + }, + }, + { + name: "DefendSQLInjectionPayload/UNIONBased/ColumnTypeDetermination", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLParams: []string{" UNION SELECT 'a',NULL,NULL;--"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLJSONParams: []any{" UNION SELECT 'a',NULL,NULL;--"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = ' UNION SELECT \\'a\\',NULL,NULL;--'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{" UNION SELECT 'a',NULL,NULL;--"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = ' UNION SELECT \\'a\\',NULL,NULL;--'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{" UNION SELECT 'a',NULL,NULL;--"}, + }, + }, + { + name: "DefendSQLInjectionPayload/UNIONBased/UNIONAllOverride", + + whereSQLParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLParams: []string{" UNION SELECT other_column1, other_column2, other_column3 FROM other_table"}, + }, + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column = ?", + WhereSQLJSONParams: []any{" UNION SELECT other_column1, other_column2, other_column3 FROM other_table"}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = ' UNION SELECT other_column1, other_column2, other_column3 FROM other_table'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{" UNION SELECT other_column1, other_column2, other_column3 FROM other_table"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = ' UNION SELECT other_column1, other_column2, other_column3 FROM other_table'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{" UNION SELECT other_column1, other_column2, other_column3 FROM other_table"}, + }, + }, + } + + for _, tc := range commonTestCases { + tc := tc + + t.Run(fmt.Sprintf("%s/%s", "WhereSQLParams", tc.name), func(t *testing.T) { + testSQLQueriesAssertion( + t, + tc.whereSQLParams, + tc.testSQLQueriesAssertionTestCase, + func(query *gorm.DB, params URLQueryWhereSQLParams) (*gorm.DB, error) { + return applyListOptionsURLQueryParameterizedQueryToWhereClause(query, params), nil + }, + ) + }) + } + for _, tc := range commonTestCases { + tc := tc + + t.Run(fmt.Sprintf("%s/%s", "WhereSQLJSONParams", tc.name), func(t *testing.T) { + testSQLQueriesAssertion( + t, + tc.whereSQLJSONParams, + tc.testSQLQueriesAssertionTestCase, + func(query *gorm.DB, params URLQueryWhereSQLParams) (*gorm.DB, error) { + return applyListOptionsURLQueryParameterizedQueryToWhereClause(query, params), nil + }, + ) + }) + } + + now := time.Now() + + advancedWhereClauseWithWhereSQLJSONParamsTestCases := []applyListOptionsURLQueryParameterizedQueryToWhereClauseTestCase{ + { + name: "WithWhereSQLJSONParameters/IN", + + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column IN ?", + WhereSQLJSONParams: []any{[]string{"value1", "value2"}}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column IN ('value1','value2')", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column IN ($1,$2)", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column IN \\(\\$1,\\$2\\)", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1", "value2"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column IN ('value1','value2')", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column IN (?,?)", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column IN \\(\\?,\\?\\)", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1", "value2"}, + }, + }, + { + name: "WithWhereSQLJSONParameters/NOT-IN", + + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column NOT IN ?", + WhereSQLJSONParams: []any{[]string{"value1", "value2"}}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column NOT IN ('value1','value2')", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column NOT IN ($1,$2)", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column NOT IN \\(\\$1,\\$2\\)", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1", "value2"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column NOT IN ('value1','value2')", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column NOT IN (?,?)", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column NOT IN \\(\\?,\\?\\)", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1", "value2"}, + }, + }, + { + name: "WithWhereSQLJSONParameters/SpecialDataTypes/time.Time", + + whereSQLJSONParams: URLQueryWhereSQLParams{ + WhereSQLStatement: "test_column <= ?", + WhereSQLJSONParams: []any{now}, + }, + + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: fmt.Sprintf("SELECT * FROM \"resources\" WHERE test_column <= '%s'", now.Format("2006-01-02 15:04:05.999")), + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column <= $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column <= \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{now}, + + mysqlRawQuery: fmt.Sprintf("SELECT * FROM `resources` WHERE test_column <= '%s'", now.Format("2006-01-02 15:04:05.999")), + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column <= ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column <= \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{now}, + }, + }, + } + + for _, tc := range advancedWhereClauseWithWhereSQLJSONParamsTestCases { + tc := tc + t.Run(fmt.Sprintf("%s/%s", "WhereSQLJSONParams", tc.name), func(t *testing.T) { + testSQLQueriesAssertion( + t, + tc.whereSQLJSONParams, + tc.testSQLQueriesAssertionTestCase, + func(query *gorm.DB, params URLQueryWhereSQLParams) (*gorm.DB, error) { + return applyListOptionsURLQueryParameterizedQueryToWhereClause(query, params), nil + }, + ) + }) + } +} + +func TestApplyListOptionsURLQueryToWhereClause(t *testing.T) { + type testCase struct { + testSQLQueriesAssertionTestCase + + name string + + allowRawSQLQueryEnabled bool + allowParameterizedSQLQueryEnabled bool + urlValues url.Values + } + + corruptedBase64Payload := "A===" + _, corruptedBase64PayloadError := base64.StdEncoding.DecodeString(corruptedBase64Payload) + require.Error(t, corruptedBase64PayloadError) + + featureGateRelatedTestCases := []testCase{ + { + name: "WithURLQueryWhereSQL/NoFeatureGateEnabled", + allowRawSQLQueryEnabled: false, + allowParameterizedSQLQueryEnabled: false, + urlValues: url.Values{ + URLQueryWhereSQL: []string{"test_column = value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\"", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\"", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\"", + + mysqlRawQuery: "SELECT * FROM `resources`", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources`", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources`", + }, + }, + { + name: "WithURLQueryFieldWhereSQLStatement/NoFeatureGateEnabled", + allowRawSQLQueryEnabled: false, + allowParameterizedSQLQueryEnabled: false, + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\"", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\"", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\"", + + mysqlRawQuery: "SELECT * FROM `resources`", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources`", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources`", + }, + }, + { + name: "WithURLQueryWhereSQL/AllowRawSQLQueryEnabled", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: false, + urlValues: url.Values{ + URLQueryWhereSQL: []string{"test_column = value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1", + }, + }, + { + name: "WithURLQueryFieldWhereSQLStatementWithParams/AllowRawSQLQueryEnabled", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: false, + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = 'value1'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = 'value1'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1"}, + }, + }, + { + name: "WithURLQueryWhereSQL/AllowParameterizedSQLQueryEnabled", + allowRawSQLQueryEnabled: false, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryWhereSQL: []string{"test_column = value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\"", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\"", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\"", + + mysqlRawQuery: "SELECT * FROM `resources`", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources`", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources`", + }, + }, + { + name: "WithURLQueryFieldWhereSQLStatementWithParams/AllowParameterizedSQLQueryEnabled", + allowRawSQLQueryEnabled: false, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = 'value1'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = 'value1'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1"}, + }, + }, + } + + for _, tc := range featureGateRelatedTestCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + testSQLQueriesAssertion( + t, + tc.urlValues, + tc.testSQLQueriesAssertionTestCase, + func(query *gorm.DB, urlValues url.Values) (*gorm.DB, error) { + return applyListOptionsURLQueryToWhereClause(query, urlValues, tc.allowRawSQLQueryEnabled, tc.allowParameterizedSQLQueryEnabled) + }, + ) + }) + } + + urlQueryFieldWhereSQLJSONParamsBase64DecodingErrorPayload, urlQueryFieldWhereSQLJSONParamsBase64DecodingError := newURLQueryFieldWhereSQLJSONParamsBase64DecodingError() + + testCases := []testCase{ + { + name: "Empty", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{}, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\"", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\"", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\"", + + mysqlRawQuery: "SELECT * FROM `resources`", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources`", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources`", + }, + }, + { + name: "WhereSQLStatementWithoutParams", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1", + }, + }, + { + name: "WhereSQLWithoutParams", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryWhereSQL: []string{"test_column = value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1", + }, + }, + { + name: "WhereSQLWithParams", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryWhereSQL: []string{"test_column = value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = value1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = value1", + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = value1", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = value1", + }, + }, + { + name: "WhereSQLStatementWithParams", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLParam: []string{"value1"}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + postgresRawQuery: "SELECT * FROM \"resources\" WHERE test_column = 'value1'", + postgresUnexplainedRawQuery: "SELECT * FROM \"resources\" WHERE test_column = $1", + postgresSqlmockDBExecutedQuery: "SELECT \\* FROM \"resources\" WHERE test_column = \\$1", + postgresSqlmockDBExecutedArgs: []driver.Value{"value1"}, + + mysqlRawQuery: "SELECT * FROM `resources` WHERE test_column = 'value1'", + mysqlUnexplainedRawQuery: "SELECT * FROM `resources` WHERE test_column = ?", + mysqlSqlmockDBExecutedQuery: "SELECT \\* FROM `resources` WHERE test_column = \\?", + mysqlSqlmockDBExecutedArgs: []driver.Value{"value1"}, + }, + }, + { + name: "ErrorHandling", + allowRawSQLQueryEnabled: true, + allowParameterizedSQLQueryEnabled: true, + urlValues: url.Values{ + URLQueryFieldWhereSQLStatement: []string{"test_column = ?"}, + URLQueryFieldWhereSQLJSONParams: []string{urlQueryFieldWhereSQLJSONParamsBase64DecodingErrorPayload}, + }, + testSQLQueriesAssertionTestCase: testSQLQueriesAssertionTestCase{ + expectedError: urlQueryFieldWhereSQLJSONParamsBase64DecodingError, + }, + }, + } + + for _, tc := range testCases { + tc := tc + + t.Run(tc.name, func(t *testing.T) { + testSQLQueriesAssertion( + t, + tc.urlValues, + tc.testSQLQueriesAssertionTestCase, + func(query *gorm.DB, urlValues url.Values) (*gorm.DB, error) { + return applyListOptionsURLQueryToWhereClause(query, urlValues, tc.allowRawSQLQueryEnabled, tc.allowParameterizedSQLQueryEnabled) + }, + ) + }) + } } func assertError(t *testing.T, expectedErr string, err error) { diff --git a/vendor/github.com/stretchr/testify/require/doc.go b/vendor/github.com/stretchr/testify/require/doc.go new file mode 100644 index 000000000..169de3922 --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/doc.go @@ -0,0 +1,28 @@ +// Package require implements the same assertions as the `assert` package but +// stops test execution when a test fails. +// +// Example Usage +// +// The following is a complete example using require in a standard test function: +// import ( +// "testing" +// "github.com/stretchr/testify/require" +// ) +// +// func TestSomething(t *testing.T) { +// +// var a string = "Hello" +// var b string = "Hello" +// +// require.Equal(t, a, b, "The two words should be the same.") +// +// } +// +// Assertions +// +// The `require` package have same global functions as in the `assert` package, +// but instead of returning a boolean result they call `t.FailNow()`. +// +// Every assertion function also takes an optional string message as the final argument, +// allowing custom error messages to be appended to the message the assertion method outputs. +package require diff --git a/vendor/github.com/stretchr/testify/require/forward_requirements.go b/vendor/github.com/stretchr/testify/require/forward_requirements.go new file mode 100644 index 000000000..1dcb2338c --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/forward_requirements.go @@ -0,0 +1,16 @@ +package require + +// Assertions provides assertion methods around the +// TestingT interface. +type Assertions struct { + t TestingT +} + +// New makes a new Assertions object for the specified TestingT. +func New(t TestingT) *Assertions { + return &Assertions{ + t: t, + } +} + +//go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" diff --git a/vendor/github.com/stretchr/testify/require/require.go b/vendor/github.com/stretchr/testify/require/require.go new file mode 100644 index 000000000..880853f5a --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go @@ -0,0 +1,1935 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Condition(t, comp, msgAndArgs...) { + return + } + t.FailNow() +} + +// Conditionf uses a Comparison to assert a complex condition. +func Conditionf(t TestingT, comp assert.Comparison, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Conditionf(t, comp, msg, args...) { + return + } + t.FailNow() +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// assert.Contains(t, "Hello World", "World") +// assert.Contains(t, ["Hello", "World"], "World") +// assert.Contains(t, {"Hello": "World"}, "Hello") +func Contains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Contains(t, s, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// 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") +func Containsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Containsf(t, s, contains, msg, args...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.DirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.DirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// 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. +// +// assert.ElementsMatch(t, [1, 3, 2, 3], [1, 3, 3, 2]) +func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ElementsMatch(t, listA, listB, msgAndArgs...) { + return + } + t.FailNow() +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// 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. +// +// assert.ElementsMatchf(t, [1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ElementsMatchf(t, listA, listB, msg, args...) { + return + } + t.FailNow() +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Empty(t, obj) +func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Empty(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// assert.Emptyf(t, obj, "error message %s", "formatted") +func Emptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Emptyf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Equal(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualError(t, err, expectedErrorString) +func EqualError(t TestingT, theError error, errString string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualError(t, theError, errString, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// assert.EqualErrorf(t, err, expectedErrorString, "error message %s", "formatted") +func EqualErrorf(t TestingT, theError error, errString string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualErrorf(t, theError, errString, msg, args...) { + return + } + t.FailNow() +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValues(t, uint32(123), int32(123)) +func EqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// assert.EqualValuesf(t, uint32(123), int32(123), "error message %s", "formatted") +func EqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.EqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Equalf asserts that two objects are equal. +// +// assert.Equalf(t, 123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equalf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Equalf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Error(t, err) { +// assert.Equal(t, expectedError, err) +// } +func Error(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Error(t, err, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func ErrorAsf(t TestingT, err error, target interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorAsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContains(t, err, expectedErrorSubString) +func ErrorContains(t TestingT, theError error, contains string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorContains(t, theError, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// assert.ErrorContainsf(t, err, expectedErrorSubString, "error message %s", "formatted") +func ErrorContainsf(t TestingT, theError error, contains string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorContainsf(t, theError, contains, msg, args...) { + return + } + t.FailNow() +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func ErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.ErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if assert.Errorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +func Errorf(t TestingT, err error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Errorf(t, err, msg, args...) { + return + } + t.FailNow() +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventually(t, func() bool { return true; }, time.Second, 10*time.Millisecond) +func Eventually(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Eventually(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// assert.Eventuallyf(t, func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Eventuallyf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + +// Exactly asserts that two objects are equal in value and type. +// +// assert.Exactly(t, int32(123), int64(123)) +func Exactly(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Exactly(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// assert.Exactlyf(t, int32(123), int64(123), "error message %s", "formatted") +func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Exactlyf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Fail(t, failureMessage, msgAndArgs...) { + return + } + t.FailNow() +} + +// FailNow fails test +func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FailNow(t, failureMessage, msgAndArgs...) { + return + } + t.FailNow() +} + +// FailNowf fails test +func FailNowf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FailNowf(t, failureMessage, msg, args...) { + return + } + t.FailNow() +} + +// Failf reports a failure through +func Failf(t TestingT, failureMessage string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Failf(t, failureMessage, msg, args...) { + return + } + t.FailNow() +} + +// False asserts that the specified value is false. +// +// assert.False(t, myBool) +func False(t TestingT, value bool, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.False(t, value, msgAndArgs...) { + return + } + t.FailNow() +} + +// Falsef asserts that the specified value is false. +// +// assert.Falsef(t, myBool, "error message %s", "formatted") +func Falsef(t TestingT, value bool, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Falsef(t, value, msg, args...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.FileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Greater(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqual(t, 2, 1) +// assert.GreaterOrEqual(t, 2, 2) +// assert.GreaterOrEqual(t, "b", "a") +// assert.GreaterOrEqual(t, "b", "b") +func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.GreaterOrEqual(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// assert.GreaterOrEqualf(t, 2, 1, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "a", "error message %s", "formatted") +// assert.GreaterOrEqualf(t, "b", "b", "error message %s", "formatted") +func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.GreaterOrEqualf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Greaterf asserts that the first element is greater than the second +// +// assert.Greaterf(t, 2, 1, "error message %s", "formatted") +// assert.Greaterf(t, float64(2), float64(1), "error message %s", "formatted") +// assert.Greaterf(t, "b", "a", "error message %s", "formatted") +func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Greaterf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// 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). +func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + t.FailNow() +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyNotContains(t, handler, method, url, values, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// 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). +func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPBodyNotContainsf(t, handler, method, url, values, str, msg, args...) { + return + } + t.FailNow() +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPError(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPError(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// assert.HTTPErrorf(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPErrorf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPRedirect(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// assert.HTTPRedirectf(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPRedirectf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCode(t, handler, method, url, values, statuscode, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// assert.HTTPStatusCodef(t, myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPStatusCodef(t, handler, method, url, values, statuscode, msg, args...) { + return + } + t.FailNow() +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) +// +// Returns whether the assertion was successful (true) or not (false). +func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, url string, values url.Values, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPSuccess(t, handler, method, url, values, msgAndArgs...) { + return + } + t.FailNow() +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// assert.HTTPSuccessf(t, myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.HTTPSuccessf(t, handler, method, url, values, msg, args...) { + return + } + t.FailNow() +} + +// Implements asserts that an object is implemented by the specified interface. +// +// assert.Implements(t, (*MyInterface)(nil), new(MyObject)) +func Implements(t TestingT, interfaceObject interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Implements(t, interfaceObject, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// assert.Implementsf(t, (*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +func Implementsf(t TestingT, interfaceObject interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Implementsf(t, interfaceObject, object, msg, args...) { + return + } + t.FailNow() +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// assert.InDelta(t, math.Pi, 22/7.0, 0.01) +func InDelta(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDelta(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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 interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaMapValues(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaMapValuesf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, delta float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaSlice(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaSlicef(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// assert.InDeltaf(t, math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +func InDeltaf(t TestingT, expected interface{}, actual interface{}, delta float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InDeltaf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +func InEpsilon(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilon(t, expected, actual, epsilon, msgAndArgs...) { + return + } + t.FailNow() +} + +// InEpsilonSlice is the same as InEpsilon, except it compares each value from two slices. +func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}, epsilon float64, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonSlice(t, expected, actual, epsilon, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonSlicef(t, expected, actual, epsilon, msg, args...) { + return + } + t.FailNow() +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +func InEpsilonf(t TestingT, expected interface{}, actual interface{}, epsilon float64, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.InEpsilonf(t, expected, actual, epsilon, msg, args...) { + return + } + t.FailNow() +} + +// IsDecreasing asserts that the collection is decreasing +// +// assert.IsDecreasing(t, []int{2, 1, 0}) +// assert.IsDecreasing(t, []float{2, 1}) +// assert.IsDecreasing(t, []string{"b", "a"}) +func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsDecreasingf asserts that the collection is decreasing +// +// assert.IsDecreasingf(t, []int{2, 1, 0}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsDecreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsIncreasing asserts that the collection is increasing +// +// assert.IsIncreasing(t, []int{1, 2, 3}) +// assert.IsIncreasing(t, []float{1, 2}) +// assert.IsIncreasing(t, []string{"a", "b"}) +func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsIncreasingf asserts that the collection is increasing +// +// assert.IsIncreasingf(t, []int{1, 2, 3}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsIncreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// assert.IsNonDecreasing(t, []int{1, 1, 2}) +// assert.IsNonDecreasing(t, []float{1, 2}) +// assert.IsNonDecreasing(t, []string{"a", "b"}) +func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// assert.IsNonDecreasingf(t, []int{1, 1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []float{1, 2}, "error message %s", "formatted") +// assert.IsNonDecreasingf(t, []string{"a", "b"}, "error message %s", "formatted") +func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonDecreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// assert.IsNonIncreasing(t, []int{2, 1, 1}) +// assert.IsNonIncreasing(t, []float{2, 1}) +// assert.IsNonIncreasing(t, []string{"b", "a"}) +func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasing(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// assert.IsNonIncreasingf(t, []int{2, 1, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []float{2, 1}, "error message %s", "formatted") +// assert.IsNonIncreasingf(t, []string{"b", "a"}, "error message %s", "formatted") +func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsNonIncreasingf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// IsType asserts that the specified objects are of the same type. +func IsType(t TestingT, expectedType interface{}, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsType(t, expectedType, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// IsTypef asserts that the specified objects are of the same type. +func IsTypef(t TestingT, expectedType interface{}, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.IsTypef(t, expectedType, object, msg, args...) { + return + } + t.FailNow() +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// assert.JSONEq(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// assert.JSONEqf(t, `{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +func JSONEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.JSONEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// assert.Len(t, mySlice, 3) +func Len(t TestingT, object interface{}, length int, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Len(t, object, length, msgAndArgs...) { + return + } + t.FailNow() +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// assert.Lenf(t, mySlice, 3, "error message %s", "formatted") +func Lenf(t TestingT, object interface{}, length int, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Lenf(t, object, length, msg, args...) { + return + } + t.FailNow() +} + +// Less asserts that the first element is less than the second +// +// assert.Less(t, 1, 2) +// assert.Less(t, float64(1), float64(2)) +// assert.Less(t, "a", "b") +func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Less(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// assert.LessOrEqual(t, 1, 2) +// assert.LessOrEqual(t, 2, 2) +// assert.LessOrEqual(t, "a", "b") +// assert.LessOrEqual(t, "b", "b") +func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.LessOrEqual(t, e1, e2, msgAndArgs...) { + return + } + t.FailNow() +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// assert.LessOrEqualf(t, 1, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, 2, 2, "error message %s", "formatted") +// assert.LessOrEqualf(t, "a", "b", "error message %s", "formatted") +// assert.LessOrEqualf(t, "b", "b", "error message %s", "formatted") +func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.LessOrEqualf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Lessf asserts that the first element is less than the second +// +// assert.Lessf(t, 1, 2, "error message %s", "formatted") +// assert.Lessf(t, float64(1), float64(2), "error message %s", "formatted") +// assert.Lessf(t, "a", "b", "error message %s", "formatted") +func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Lessf(t, e1, e2, msg, args...) { + return + } + t.FailNow() +} + +// Negative asserts that the specified element is negative +// +// assert.Negative(t, -1) +// assert.Negative(t, -1.23) +func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negative(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Negativef asserts that the specified element is negative +// +// assert.Negativef(t, -1, "error message %s", "formatted") +// assert.Negativef(t, -1.23, "error message %s", "formatted") +func Negativef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Negativef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Never(t, func() bool { return false; }, time.Second, 10*time.Millisecond) +func Never(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Never(t, condition, waitFor, tick, msgAndArgs...) { + return + } + t.FailNow() +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// assert.Neverf(t, func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func Neverf(t TestingT, condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Neverf(t, condition, waitFor, tick, msg, args...) { + return + } + t.FailNow() +} + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Nil(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// Nilf asserts that the specified object is nil. +// +// assert.Nilf(t, err, "error message %s", "formatted") +func Nilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Nilf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func NoDirExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoDirExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoError(t, err, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoErrorf(t, err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoErrorf(t TestingT, err error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoErrorf(t, err, msg, args...) { + return + } + t.FailNow() +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExists(t, path, msgAndArgs...) { + return + } + t.FailNow() +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func NoFileExistsf(t TestingT, path string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoFileExistsf(t, path, msg, args...) { + return + } + t.FailNow() +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// assert.NotContains(t, "Hello World", "Earth") +// assert.NotContains(t, ["Hello", "World"], "Earth") +// assert.NotContains(t, {"Hello": "World"}, "Earth") +func NotContains(t TestingT, s interface{}, contains interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotContains(t, s, contains, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// 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") +func NotContainsf(t TestingT, s interface{}, contains interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotContainsf(t, s, contains, msg, args...) { + return + } + t.FailNow() +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmpty(t, obj) { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEmpty(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if assert.NotEmptyf(t, obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +func NotEmptyf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEmptyf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NotEqual asserts that the specified values are NOT equal. +// +// assert.NotEqual(t, obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqual(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqual(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValues(t, obj1, obj2) +func NotEqualValues(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValues(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// assert.NotEqualValuesf(t, obj1, obj2, "error message %s", "formatted") +func NotEqualValuesf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualValuesf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// assert.NotEqualf(t, obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotEqualf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIs(t, err, target, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func NotErrorIsf(t TestingT, err error, target error, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotErrorIsf(t, err, target, msg, args...) { + return + } + t.FailNow() +} + +// NotNil asserts that the specified object is not nil. +// +// assert.NotNil(t, err) +func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotNil(t, object, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotNilf asserts that the specified object is not nil. +// +// assert.NotNilf(t, err, "error message %s", "formatted") +func NotNilf(t TestingT, object interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotNilf(t, object, msg, args...) { + return + } + t.FailNow() +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanics(t, func(){ RemainCalm() }) +func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotPanics(t, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// assert.NotPanicsf(t, func(){ RemainCalm() }, "error message %s", "formatted") +func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotPanicsf(t, f, msg, args...) { + return + } + t.FailNow() +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// assert.NotRegexp(t, regexp.MustCompile("starts"), "it's starting") +// assert.NotRegexp(t, "^start", "it's not starting") +func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotRegexp(t, rx, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// assert.NotRegexpf(t, regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// assert.NotRegexpf(t, "^start", "it's not starting", "error message %s", "formatted") +func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotRegexpf(t, rx, str, msg, args...) { + return + } + t.FailNow() +} + +// NotSame asserts that two pointers do not reference the same object. +// +// assert.NotSame(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSame(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSame(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// assert.NotSamef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func NotSamef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSamef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// 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]") +func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSubset(t, list, subset, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// 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") +func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotSubsetf(t, list, subset, msg, args...) { + return + } + t.FailNow() +} + +// NotZero asserts that i is not the zero value for its type. +func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotZero(t, i, msgAndArgs...) { + return + } + t.FailNow() +} + +// NotZerof asserts that i is not the zero value for its type. +func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NotZerof(t, i, msg, args...) { + return + } + t.FailNow() +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panics(t, func(){ GoCrazy() }) +func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Panics(t, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithError(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithError(t TestingT, errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithError(t, errString, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// assert.PanicsWithErrorf(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithErrorf(t, errString, f, msg, args...) { + return + } + t.FailNow() +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValue(t, "crazy error", func(){ GoCrazy() }) +func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithValue(t, expected, f, msgAndArgs...) { + return + } + t.FailNow() +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// assert.PanicsWithValuef(t, "crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.PanicsWithValuef(t, expected, f, msg, args...) { + return + } + t.FailNow() +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// assert.Panicsf(t, func(){ GoCrazy() }, "error message %s", "formatted") +func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Panicsf(t, f, msg, args...) { + return + } + t.FailNow() +} + +// Positive asserts that the specified element is positive +// +// assert.Positive(t, 1) +// assert.Positive(t, 1.23) +func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positive(t, e, msgAndArgs...) { + return + } + t.FailNow() +} + +// Positivef asserts that the specified element is positive +// +// assert.Positivef(t, 1, "error message %s", "formatted") +// assert.Positivef(t, 1.23, "error message %s", "formatted") +func Positivef(t TestingT, e interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Positivef(t, e, msg, args...) { + return + } + t.FailNow() +} + +// Regexp asserts that a specified regexp matches a string. +// +// assert.Regexp(t, regexp.MustCompile("start"), "it's starting") +// assert.Regexp(t, "start...$", "it's not starting") +func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Regexp(t, rx, str, msgAndArgs...) { + return + } + t.FailNow() +} + +// Regexpf asserts that a specified regexp matches a string. +// +// assert.Regexpf(t, regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// assert.Regexpf(t, "start...$", "it's not starting", "error message %s", "formatted") +func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Regexpf(t, rx, str, msg, args...) { + return + } + t.FailNow() +} + +// Same asserts that two pointers reference the same object. +// +// assert.Same(t, ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Same(t TestingT, expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Same(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// Samef asserts that two pointers reference the same object. +// +// assert.Samef(t, ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func Samef(t TestingT, expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Samef(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// assert.Subset(t, [1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Subset(t, list, subset, msgAndArgs...) { + return + } + t.FailNow() +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// 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") +func Subsetf(t TestingT, list interface{}, subset interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Subsetf(t, list, subset, msg, args...) { + return + } + t.FailNow() +} + +// True asserts that the specified value is true. +// +// assert.True(t, myBool) +func True(t TestingT, value bool, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.True(t, value, msgAndArgs...) { + return + } + t.FailNow() +} + +// Truef asserts that the specified value is true. +// +// assert.Truef(t, myBool, "error message %s", "formatted") +func Truef(t TestingT, value bool, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Truef(t, value, msg, args...) { + return + } + t.FailNow() +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// assert.WithinDuration(t, time.Now(), time.Now(), 10*time.Second) +func WithinDuration(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinDuration(t, expected, actual, delta, msgAndArgs...) { + return + } + t.FailNow() +} + +// 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") +func WithinDurationf(t TestingT, expected time.Time, actual time.Time, delta time.Duration, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinDurationf(t, expected, actual, delta, msg, args...) { + return + } + t.FailNow() +} + +// WithinRange asserts that a time is within a time range (inclusive). +// +// assert.WithinRange(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +func WithinRange(t TestingT, actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinRange(t, actual, start, end, msgAndArgs...) { + return + } + t.FailNow() +} + +// WithinRangef asserts that a time is within a time range (inclusive). +// +// assert.WithinRangef(t, time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +func WithinRangef(t TestingT, actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.WithinRangef(t, actual, start, end, msg, args...) { + return + } + t.FailNow() +} + +// YAMLEq asserts that two YAML strings are equivalent. +func YAMLEq(t TestingT, expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEq(t, expected, actual, msgAndArgs...) { + return + } + t.FailNow() +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func YAMLEqf(t TestingT, expected string, actual string, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.YAMLEqf(t, expected, actual, msg, args...) { + return + } + t.FailNow() +} + +// Zero asserts that i is the zero value for its type. +func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Zero(t, i, msgAndArgs...) { + return + } + t.FailNow() +} + +// Zerof asserts that i is the zero value for its type. +func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.Zerof(t, i, msg, args...) { + return + } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require.go.tmpl b/vendor/github.com/stretchr/testify/require/require.go.tmpl new file mode 100644 index 000000000..55e42ddeb --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require.go.tmpl @@ -0,0 +1,6 @@ +{{.Comment}} +func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { + if h, ok := t.(tHelper); ok { h.Helper() } + if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } + t.FailNow() +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go b/vendor/github.com/stretchr/testify/require/require_forward.go new file mode 100644 index 000000000..960bf6f2c --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go @@ -0,0 +1,1515 @@ +/* +* CODE GENERATED AUTOMATICALLY WITH github.com/stretchr/testify/_codegen +* THIS FILE MUST NOT BE EDITED BY HAND + */ + +package require + +import ( + assert "github.com/stretchr/testify/assert" + http "net/http" + url "net/url" + time "time" +) + +// Condition uses a Comparison to assert a complex condition. +func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Condition(a.t, comp, msgAndArgs...) +} + +// Conditionf uses a Comparison to assert a complex condition. +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...) +} + +// Contains asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// a.Contains("Hello World", "World") +// a.Contains(["Hello", "World"], "World") +// a.Contains({"Hello": "World"}, "Hello") +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...) +} + +// Containsf asserts that the specified string, list(array, slice...) or map contains the +// specified substring or element. +// +// 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") +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...) +} + +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + 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. +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...) +} + +// ElementsMatch asserts that the specified listA(array, slice...) is equal to specified +// 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. +// +// a.ElementsMatch([1, 3, 2, 3], [1, 3, 3, 2]) +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...) +} + +// ElementsMatchf asserts that the specified listA(array, slice...) is equal to specified +// 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. +// +// a.ElementsMatchf([1, 3, 2, 3], [1, 3, 3, 2], "error message %s", "formatted") +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...) +} + +// Empty asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Empty(obj) +func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Empty(a.t, object, msgAndArgs...) +} + +// Emptyf asserts that the specified object is empty. I.e. nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// a.Emptyf(obj, "error message %s", "formatted") +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...) +} + +// Equal asserts that two objects are equal. +// +// a.Equal(123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +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...) +} + +// EqualError asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualError(err, expectedErrorString) +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...) +} + +// EqualErrorf asserts that a function returned an error (i.e. not `nil`) +// and that it is equal to the provided error. +// +// actualObj, err := SomeFunction() +// a.EqualErrorf(err, expectedErrorString, "error message %s", "formatted") +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...) +} + +// EqualValues asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValues(uint32(123), int32(123)) +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...) +} + +// EqualValuesf asserts that two objects are equal or convertable to the same types +// and equal. +// +// a.EqualValuesf(uint32(123), int32(123), "error message %s", "formatted") +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...) +} + +// Equalf asserts that two objects are equal. +// +// a.Equalf(123, 123, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +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...) +} + +// Error asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Error(err) { +// assert.Equal(t, expectedError, err) +// } +func (a *Assertions) Error(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Error(a.t, err, msgAndArgs...) +} + +// ErrorAs asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAs(a.t, err, target, msgAndArgs...) +} + +// ErrorAsf asserts that at least one of the errors in err's chain matches target, and if so, sets target to that error value. +// This is a wrapper for errors.As. +func (a *Assertions) ErrorAsf(err error, target interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorAsf(a.t, err, target, msg, args...) +} + +// ErrorContains asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContains(err, expectedErrorSubString) +func (a *Assertions) ErrorContains(theError error, contains string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorContains(a.t, theError, contains, msgAndArgs...) +} + +// ErrorContainsf asserts that a function returned an error (i.e. not `nil`) +// and that the error contains the specified substring. +// +// actualObj, err := SomeFunction() +// a.ErrorContainsf(err, expectedErrorSubString, "error message %s", "formatted") +func (a *Assertions) ErrorContainsf(theError error, contains string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorContainsf(a.t, theError, contains, msg, args...) +} + +// ErrorIs asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIs(a.t, err, target, msgAndArgs...) +} + +// ErrorIsf asserts that at least one of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + ErrorIsf(a.t, err, target, msg, args...) +} + +// Errorf asserts that a function returned an error (i.e. not `nil`). +// +// actualObj, err := SomeFunction() +// if a.Errorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedErrorf, err) +// } +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...) +} + +// Eventually asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventually(func() bool { return true; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Eventually(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Eventually(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Eventuallyf asserts that given condition will be met in waitFor time, +// periodically checking target function each tick. +// +// a.Eventuallyf(func() bool { return true; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Eventuallyf(a.t, condition, waitFor, tick, msg, args...) +} + +// Exactly asserts that two objects are equal in value and type. +// +// a.Exactly(int32(123), int64(123)) +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...) +} + +// Exactlyf asserts that two objects are equal in value and type. +// +// a.Exactlyf(int32(123), int64(123), "error message %s", "formatted") +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...) +} + +// Fail reports a failure through +func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Fail(a.t, failureMessage, msgAndArgs...) +} + +// FailNow fails test +func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + FailNow(a.t, failureMessage, msgAndArgs...) +} + +// FailNowf fails test +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...) +} + +// Failf reports a failure through +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...) +} + +// False asserts that the specified value is false. +// +// a.False(myBool) +func (a *Assertions) False(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + False(a.t, value, msgAndArgs...) +} + +// Falsef asserts that the specified value is false. +// +// a.Falsef(myBool, "error message %s", "formatted") +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...) +} + +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + 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. +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...) +} + +// Greater asserts that the first element is greater than the second +// +// a.Greater(2, 1) +// a.Greater(float64(2), float64(1)) +// a.Greater("b", "a") +func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Greater(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqual asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqual(2, 1) +// a.GreaterOrEqual(2, 2) +// a.GreaterOrEqual("b", "a") +// a.GreaterOrEqual("b", "b") +func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + GreaterOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// GreaterOrEqualf asserts that the first element is greater than or equal to the second +// +// a.GreaterOrEqualf(2, 1, "error message %s", "formatted") +// a.GreaterOrEqualf(2, 2, "error message %s", "formatted") +// a.GreaterOrEqualf("b", "a", "error message %s", "formatted") +// a.GreaterOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + GreaterOrEqualf(a.t, e1, e2, msg, args...) +} + +// Greaterf asserts that the first element is greater than the second +// +// a.Greaterf(2, 1, "error message %s", "formatted") +// a.Greaterf(float64(2), float64(1), "error message %s", "formatted") +// a.Greaterf("b", "a", "error message %s", "formatted") +func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Greaterf(a.t, e1, e2, msg, args...) +} + +// HTTPBodyContains asserts that a specified handler returns a +// body that contains a string. +// +// a.HTTPBodyContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyContainsf asserts that a specified handler returns a +// body that contains a string. +// +// 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). +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...) +} + +// HTTPBodyNotContains asserts that a specified handler returns a +// body that does not contain a string. +// +// a.HTTPBodyNotContains(myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") +// +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPBodyNotContains(a.t, handler, method, url, values, str, msgAndArgs...) +} + +// HTTPBodyNotContainsf asserts that a specified handler returns a +// body that does not contain a string. +// +// 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). +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...) +} + +// HTTPError asserts that a specified handler returns an error status code. +// +// a.HTTPError(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPError(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPErrorf asserts that a specified handler returns an error status code. +// +// a.HTTPErrorf(myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +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...) +} + +// HTTPRedirect asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirect(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPRedirect(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPRedirectf asserts that a specified handler returns a redirect status code. +// +// a.HTTPRedirectf(myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} +// +// Returns whether the assertion was successful (true) or not (false). +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...) +} + +// HTTPStatusCode asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCode(myHandler, "GET", "/notImplemented", nil, 501) +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCode(a.t, handler, method, url, values, statuscode, msgAndArgs...) +} + +// HTTPStatusCodef asserts that a specified handler returns a specified status code. +// +// a.HTTPStatusCodef(myHandler, "GET", "/notImplemented", nil, 501, "error message %s", "formatted") +// +// Returns whether the assertion was successful (true) or not (false). +func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method string, url string, values url.Values, statuscode int, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPStatusCodef(a.t, handler, method, url, values, statuscode, msg, args...) +} + +// HTTPSuccess asserts that a specified handler returns a success status code. +// +// a.HTTPSuccess(myHandler, "POST", "http://www.google.com", nil) +// +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccess(a.t, handler, method, url, values, msgAndArgs...) +} + +// HTTPSuccessf asserts that a specified handler returns a success status code. +// +// a.HTTPSuccessf(myHandler, "POST", "http://www.google.com", nil, "error message %s", "formatted") +// +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + HTTPSuccessf(a.t, handler, method, url, values, msg, args...) +} + +// Implements asserts that an object is implemented by the specified interface. +// +// a.Implements((*MyInterface)(nil), new(MyObject)) +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...) +} + +// Implementsf asserts that an object is implemented by the specified interface. +// +// a.Implementsf((*MyInterface)(nil), new(MyObject), "error message %s", "formatted") +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...) +} + +// InDelta asserts that the two numerals are within delta of each other. +// +// a.InDelta(math.Pi, 22/7.0, 0.01) +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...) +} + +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + 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. +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...) +} + +// InDeltaSlice is the same as InDelta, except it compares two slices. +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...) +} + +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InDeltaSlicef(a.t, expected, actual, delta, msg, args...) +} + +// InDeltaf asserts that the two numerals are within delta of each other. +// +// a.InDeltaf(math.Pi, 22/7.0, 0.01, "error message %s", "formatted") +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...) +} + +// InEpsilon asserts that expected and actual have a relative error less than epsilon +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...) +} + +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlice(a.t, expected, actual, epsilon, msgAndArgs...) +} + +// 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{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + InEpsilonSlicef(a.t, expected, actual, epsilon, msg, args...) +} + +// InEpsilonf asserts that expected and actual have a relative error less than epsilon +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...) +} + +// IsDecreasing asserts that the collection is decreasing +// +// a.IsDecreasing([]int{2, 1, 0}) +// a.IsDecreasing([]float{2, 1}) +// a.IsDecreasing([]string{"b", "a"}) +func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasing(a.t, object, msgAndArgs...) +} + +// IsDecreasingf asserts that the collection is decreasing +// +// a.IsDecreasingf([]int{2, 1, 0}, "error message %s", "formatted") +// a.IsDecreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsDecreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsDecreasingf(a.t, object, msg, args...) +} + +// IsIncreasing asserts that the collection is increasing +// +// a.IsIncreasing([]int{1, 2, 3}) +// a.IsIncreasing([]float{1, 2}) +// a.IsIncreasing([]string{"a", "b"}) +func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasing(a.t, object, msgAndArgs...) +} + +// IsIncreasingf asserts that the collection is increasing +// +// a.IsIncreasingf([]int{1, 2, 3}, "error message %s", "formatted") +// a.IsIncreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsIncreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsIncreasingf(a.t, object, msg, args...) +} + +// IsNonDecreasing asserts that the collection is not decreasing +// +// a.IsNonDecreasing([]int{1, 1, 2}) +// a.IsNonDecreasing([]float{1, 2}) +// a.IsNonDecreasing([]string{"a", "b"}) +func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasing(a.t, object, msgAndArgs...) +} + +// IsNonDecreasingf asserts that the collection is not decreasing +// +// a.IsNonDecreasingf([]int{1, 1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]float{1, 2}, "error message %s", "formatted") +// a.IsNonDecreasingf([]string{"a", "b"}, "error message %s", "formatted") +func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonDecreasingf(a.t, object, msg, args...) +} + +// IsNonIncreasing asserts that the collection is not increasing +// +// a.IsNonIncreasing([]int{2, 1, 1}) +// a.IsNonIncreasing([]float{2, 1}) +// a.IsNonIncreasing([]string{"b", "a"}) +func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasing(a.t, object, msgAndArgs...) +} + +// IsNonIncreasingf asserts that the collection is not increasing +// +// a.IsNonIncreasingf([]int{2, 1, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]float{2, 1}, "error message %s", "formatted") +// a.IsNonIncreasingf([]string{"b", "a"}, "error message %s", "formatted") +func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + IsNonIncreasingf(a.t, object, msg, args...) +} + +// IsType asserts that the specified objects are of the same type. +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...) +} + +// IsTypef asserts that the specified objects are of the same type. +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...) +} + +// JSONEq asserts that two JSON strings are equivalent. +// +// a.JSONEq(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`) +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...) +} + +// JSONEqf asserts that two JSON strings are equivalent. +// +// a.JSONEqf(`{"hello": "world", "foo": "bar"}`, `{"foo": "bar", "hello": "world"}`, "error message %s", "formatted") +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...) +} + +// Len asserts that the specified object has specific length. +// Len also fails if the object has a type that len() not accept. +// +// a.Len(mySlice, 3) +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...) +} + +// Lenf asserts that the specified object has specific length. +// Lenf also fails if the object has a type that len() not accept. +// +// a.Lenf(mySlice, 3, "error message %s", "formatted") +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...) +} + +// Less asserts that the first element is less than the second +// +// a.Less(1, 2) +// a.Less(float64(1), float64(2)) +// a.Less("a", "b") +func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Less(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqual asserts that the first element is less than or equal to the second +// +// a.LessOrEqual(1, 2) +// a.LessOrEqual(2, 2) +// a.LessOrEqual("a", "b") +// a.LessOrEqual("b", "b") +func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + LessOrEqual(a.t, e1, e2, msgAndArgs...) +} + +// LessOrEqualf asserts that the first element is less than or equal to the second +// +// a.LessOrEqualf(1, 2, "error message %s", "formatted") +// a.LessOrEqualf(2, 2, "error message %s", "formatted") +// a.LessOrEqualf("a", "b", "error message %s", "formatted") +// a.LessOrEqualf("b", "b", "error message %s", "formatted") +func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + LessOrEqualf(a.t, e1, e2, msg, args...) +} + +// Lessf asserts that the first element is less than the second +// +// a.Lessf(1, 2, "error message %s", "formatted") +// a.Lessf(float64(1), float64(2), "error message %s", "formatted") +// a.Lessf("a", "b", "error message %s", "formatted") +func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Lessf(a.t, e1, e2, msg, args...) +} + +// Negative asserts that the specified element is negative +// +// a.Negative(-1) +// a.Negative(-1.23) +func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negative(a.t, e, msgAndArgs...) +} + +// Negativef asserts that the specified element is negative +// +// a.Negativef(-1, "error message %s", "formatted") +// a.Negativef(-1.23, "error message %s", "formatted") +func (a *Assertions) Negativef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Negativef(a.t, e, msg, args...) +} + +// Never asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Never(func() bool { return false; }, time.Second, 10*time.Millisecond) +func (a *Assertions) Never(condition func() bool, waitFor time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Never(a.t, condition, waitFor, tick, msgAndArgs...) +} + +// Neverf asserts that the given condition doesn't satisfy in waitFor time, +// periodically checking the target function each tick. +// +// a.Neverf(func() bool { return false; }, time.Second, 10*time.Millisecond, "error message %s", "formatted") +func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration, tick time.Duration, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Neverf(a.t, condition, waitFor, tick, msg, args...) +} + +// Nil asserts that the specified object is nil. +// +// a.Nil(err) +func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Nil(a.t, object, msgAndArgs...) +} + +// Nilf asserts that the specified object is nil. +// +// a.Nilf(err, "error message %s", "formatted") +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...) +} + +// NoDirExists checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExists(a.t, path, msgAndArgs...) +} + +// NoDirExistsf checks whether a directory does not exist in the given path. +// It fails if the path points to an existing _directory_ only. +func (a *Assertions) NoDirExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoDirExistsf(a.t, path, msg, args...) +} + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoError(err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoError(a.t, err, msgAndArgs...) +} + +// NoErrorf asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if a.NoErrorf(err, "error message %s", "formatted") { +// assert.Equal(t, expectedObj, actualObj) +// } +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...) +} + +// NoFileExists checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExists(a.t, path, msgAndArgs...) +} + +// NoFileExistsf checks whether a file does not exist in a given path. It fails +// if the path points to an existing _file_ only. +func (a *Assertions) NoFileExistsf(path string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NoFileExistsf(a.t, path, msg, args...) +} + +// NotContains asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// a.NotContains("Hello World", "Earth") +// a.NotContains(["Hello", "World"], "Earth") +// a.NotContains({"Hello": "World"}, "Earth") +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...) +} + +// NotContainsf asserts that the specified string, list(array, slice...) or map does NOT contain the +// specified substring or element. +// +// 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") +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...) +} + +// NotEmpty asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmpty(obj) { +// assert.Equal(t, "two", obj[1]) +// } +func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEmpty(a.t, object, msgAndArgs...) +} + +// NotEmptyf asserts that the specified object is NOT empty. I.e. not nil, "", false, 0 or either +// a slice or a channel with len == 0. +// +// if a.NotEmptyf(obj, "error message %s", "formatted") { +// assert.Equal(t, "two", obj[1]) +// } +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...) +} + +// NotEqual asserts that the specified values are NOT equal. +// +// a.NotEqual(obj1, obj2) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +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...) +} + +// NotEqualValues asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValues(obj1, obj2) +func (a *Assertions) NotEqualValues(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValues(a.t, expected, actual, msgAndArgs...) +} + +// NotEqualValuesf asserts that two objects are not equal even when converted to the same type +// +// a.NotEqualValuesf(obj1, obj2, "error message %s", "formatted") +func (a *Assertions) NotEqualValuesf(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotEqualValuesf(a.t, expected, actual, msg, args...) +} + +// NotEqualf asserts that the specified values are NOT equal. +// +// a.NotEqualf(obj1, obj2, "error message %s", "formatted") +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). +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...) +} + +// NotErrorIs asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIs(a.t, err, target, msgAndArgs...) +} + +// NotErrorIsf asserts that at none of the errors in err's chain matches target. +// This is a wrapper for errors.Is. +func (a *Assertions) NotErrorIsf(err error, target error, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotErrorIsf(a.t, err, target, msg, args...) +} + +// NotNil asserts that the specified object is not nil. +// +// a.NotNil(err) +func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotNil(a.t, object, msgAndArgs...) +} + +// NotNilf asserts that the specified object is not nil. +// +// a.NotNilf(err, "error message %s", "formatted") +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...) +} + +// NotPanics asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanics(func(){ RemainCalm() }) +func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotPanics(a.t, f, msgAndArgs...) +} + +// NotPanicsf asserts that the code inside the specified PanicTestFunc does NOT panic. +// +// a.NotPanicsf(func(){ RemainCalm() }, "error message %s", "formatted") +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...) +} + +// NotRegexp asserts that a specified regexp does not match a string. +// +// a.NotRegexp(regexp.MustCompile("starts"), "it's starting") +// a.NotRegexp("^start", "it's not starting") +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...) +} + +// NotRegexpf asserts that a specified regexp does not match a string. +// +// a.NotRegexpf(regexp.MustCompile("starts"), "it's starting", "error message %s", "formatted") +// a.NotRegexpf("^start", "it's not starting", "error message %s", "formatted") +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...) +} + +// NotSame asserts that two pointers do not reference the same object. +// +// a.NotSame(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSame(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSame(a.t, expected, actual, msgAndArgs...) +} + +// NotSamef asserts that two pointers do not reference the same object. +// +// a.NotSamef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) NotSamef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotSamef(a.t, expected, actual, msg, args...) +} + +// NotSubset asserts that the specified list(array, slice...) contains not all +// elements given in the specified subset(array, slice...). +// +// a.NotSubset([1, 3, 4], [1, 2], "But [1, 3, 4] does not contain [1, 2]") +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...) +} + +// NotSubsetf asserts that the specified list(array, slice...) contains not all +// 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") +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...) +} + +// NotZero asserts that i is not the zero value for its type. +func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + NotZero(a.t, i, msgAndArgs...) +} + +// NotZerof asserts that i is not the zero value for its type. +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...) +} + +// Panics asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panics(func(){ GoCrazy() }) +func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Panics(a.t, f, msgAndArgs...) +} + +// PanicsWithError asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithError("crazy error", func(){ GoCrazy() }) +func (a *Assertions) PanicsWithError(errString string, f assert.PanicTestFunc, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithError(a.t, errString, f, msgAndArgs...) +} + +// PanicsWithErrorf asserts that the code inside the specified PanicTestFunc +// panics, and that the recovered panic value is an error that satisfies the +// EqualError comparison. +// +// a.PanicsWithErrorf("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTestFunc, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + PanicsWithErrorf(a.t, errString, f, msg, args...) +} + +// PanicsWithValue asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValue("crazy error", func(){ GoCrazy() }) +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...) +} + +// PanicsWithValuef asserts that the code inside the specified PanicTestFunc panics, and that +// the recovered panic value equals the expected panic value. +// +// a.PanicsWithValuef("crazy error", func(){ GoCrazy() }, "error message %s", "formatted") +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...) +} + +// Panicsf asserts that the code inside the specified PanicTestFunc panics. +// +// a.Panicsf(func(){ GoCrazy() }, "error message %s", "formatted") +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...) +} + +// Positive asserts that the specified element is positive +// +// a.Positive(1) +// a.Positive(1.23) +func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positive(a.t, e, msgAndArgs...) +} + +// Positivef asserts that the specified element is positive +// +// a.Positivef(1, "error message %s", "formatted") +// a.Positivef(1.23, "error message %s", "formatted") +func (a *Assertions) Positivef(e interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Positivef(a.t, e, msg, args...) +} + +// Regexp asserts that a specified regexp matches a string. +// +// a.Regexp(regexp.MustCompile("start"), "it's starting") +// a.Regexp("start...$", "it's not starting") +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...) +} + +// Regexpf asserts that a specified regexp matches a string. +// +// a.Regexpf(regexp.MustCompile("start"), "it's starting", "error message %s", "formatted") +// a.Regexpf("start...$", "it's not starting", "error message %s", "formatted") +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...) +} + +// Same asserts that two pointers reference the same object. +// +// a.Same(ptr1, ptr2) +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Same(expected interface{}, actual interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Same(a.t, expected, actual, msgAndArgs...) +} + +// Samef asserts that two pointers reference the same object. +// +// a.Samef(ptr1, ptr2, "error message %s", "formatted") +// +// Both arguments must be pointer variables. Pointer variable sameness is +// determined based on the equality of both type and value. +func (a *Assertions) Samef(expected interface{}, actual interface{}, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Samef(a.t, expected, actual, msg, args...) +} + +// Subset asserts that the specified list(array, slice...) contains all +// elements given in the specified subset(array, slice...). +// +// a.Subset([1, 2, 3], [1, 2], "But [1, 2, 3] does contain [1, 2]") +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...) +} + +// Subsetf asserts that the specified list(array, slice...) contains all +// 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") +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...) +} + +// True asserts that the specified value is true. +// +// a.True(myBool) +func (a *Assertions) True(value bool, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + True(a.t, value, msgAndArgs...) +} + +// Truef asserts that the specified value is true. +// +// a.Truef(myBool, "error message %s", "formatted") +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...) +} + +// WithinDuration asserts that the two times are within duration delta of each other. +// +// a.WithinDuration(time.Now(), time.Now(), 10*time.Second) +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...) +} + +// 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") +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...) +} + +// WithinRange asserts that a time is within a time range (inclusive). +// +// a.WithinRange(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second)) +func (a *Assertions) WithinRange(actual time.Time, start time.Time, end time.Time, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinRange(a.t, actual, start, end, msgAndArgs...) +} + +// WithinRangef asserts that a time is within a time range (inclusive). +// +// a.WithinRangef(time.Now(), time.Now().Add(-time.Second), time.Now().Add(time.Second), "error message %s", "formatted") +func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end time.Time, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + WithinRangef(a.t, actual, start, end, msg, args...) +} + +// YAMLEq asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEq(expected string, actual string, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEq(a.t, expected, actual, msgAndArgs...) +} + +// YAMLEqf asserts that two YAML strings are equivalent. +func (a *Assertions) YAMLEqf(expected string, actual string, msg string, args ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + YAMLEqf(a.t, expected, actual, msg, args...) +} + +// Zero asserts that i is the zero value for its type. +func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) { + if h, ok := a.t.(tHelper); ok { + h.Helper() + } + Zero(a.t, i, msgAndArgs...) +} + +// Zerof asserts that i is the zero value for its type. +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...) +} diff --git a/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl new file mode 100644 index 000000000..54124df1d --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/require_forward.go.tmpl @@ -0,0 +1,5 @@ +{{.CommentWithoutT "a"}} +func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { + if h, ok := a.t.(tHelper); ok { h.Helper() } + {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) +} diff --git a/vendor/github.com/stretchr/testify/require/requirements.go b/vendor/github.com/stretchr/testify/require/requirements.go new file mode 100644 index 000000000..91772dfeb --- /dev/null +++ b/vendor/github.com/stretchr/testify/require/requirements.go @@ -0,0 +1,29 @@ +package require + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) + 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 sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" diff --git a/vendor/modules.txt b/vendor/modules.txt index f52a2e267..742ea0492 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -307,6 +307,7 @@ github.com/stoewer/go-strcase # github.com/stretchr/testify v1.8.1 ## explicit; go 1.13 github.com/stretchr/testify/assert +github.com/stretchr/testify/require # go.etcd.io/etcd/api/v3 v3.5.5 ## explicit; go 1.16 go.etcd.io/etcd/api/v3/authpb