// Code generated by mockery v0.0.0-dev. DO NOT EDIT.

package mocks

import (
	context "context"

	buildbucketpb "go.chromium.org/luci/buildbucket/proto"

	mock "github.com/stretchr/testify/mock"

	testing "testing"
)

// BuildBucketInterface is an autogenerated mock type for the BuildBucketInterface type
type BuildBucketInterface struct {
	mock.Mock
}

// CancelBuilds provides a mock function with given fields: ctx, buildIDs, summaryMarkdown
func (_m *BuildBucketInterface) CancelBuilds(ctx context.Context, buildIDs []int64, summaryMarkdown string) ([]*buildbucketpb.Build, error) {
	ret := _m.Called(ctx, buildIDs, summaryMarkdown)

	var r0 []*buildbucketpb.Build
	if rf, ok := ret.Get(0).(func(context.Context, []int64, string) []*buildbucketpb.Build); ok {
		r0 = rf(ctx, buildIDs, summaryMarkdown)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*buildbucketpb.Build)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(context.Context, []int64, string) error); ok {
		r1 = rf(ctx, buildIDs, summaryMarkdown)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GetBuild provides a mock function with given fields: ctx, buildId
func (_m *BuildBucketInterface) GetBuild(ctx context.Context, buildId int64) (*buildbucketpb.Build, error) {
	ret := _m.Called(ctx, buildId)

	var r0 *buildbucketpb.Build
	if rf, ok := ret.Get(0).(func(context.Context, int64) *buildbucketpb.Build); ok {
		r0 = rf(ctx, buildId)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*buildbucketpb.Build)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
		r1 = rf(ctx, buildId)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// GetTrybotsForCL provides a mock function with given fields: ctx, issue, patchset, gerritUrl, tags
func (_m *BuildBucketInterface) GetTrybotsForCL(ctx context.Context, issue int64, patchset int64, gerritUrl string, tags map[string]string) ([]*buildbucketpb.Build, error) {
	ret := _m.Called(ctx, issue, patchset, gerritUrl, tags)

	var r0 []*buildbucketpb.Build
	if rf, ok := ret.Get(0).(func(context.Context, int64, int64, string, map[string]string) []*buildbucketpb.Build); ok {
		r0 = rf(ctx, issue, patchset, gerritUrl, tags)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*buildbucketpb.Build)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(context.Context, int64, int64, string, map[string]string) error); ok {
		r1 = rf(ctx, issue, patchset, gerritUrl, tags)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// ScheduleBuilds provides a mock function with given fields: ctx, builds, buildsToTags, issue, patchset, gerritUrl, repo, bbProject, bbBucket
func (_m *BuildBucketInterface) ScheduleBuilds(ctx context.Context, builds []string, buildsToTags map[string]map[string]string, issue int64, patchset int64, gerritUrl string, repo string, bbProject string, bbBucket string) ([]*buildbucketpb.Build, error) {
	ret := _m.Called(ctx, builds, buildsToTags, issue, patchset, gerritUrl, repo, bbProject, bbBucket)

	var r0 []*buildbucketpb.Build
	if rf, ok := ret.Get(0).(func(context.Context, []string, map[string]map[string]string, int64, int64, string, string, string, string) []*buildbucketpb.Build); ok {
		r0 = rf(ctx, builds, buildsToTags, issue, patchset, gerritUrl, repo, bbProject, bbBucket)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*buildbucketpb.Build)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(context.Context, []string, map[string]map[string]string, int64, int64, string, string, string, string) error); ok {
		r1 = rf(ctx, builds, buildsToTags, issue, patchset, gerritUrl, repo, bbProject, bbBucket)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// Search provides a mock function with given fields: ctx, pred
func (_m *BuildBucketInterface) Search(ctx context.Context, pred *buildbucketpb.BuildPredicate) ([]*buildbucketpb.Build, error) {
	ret := _m.Called(ctx, pred)

	var r0 []*buildbucketpb.Build
	if rf, ok := ret.Get(0).(func(context.Context, *buildbucketpb.BuildPredicate) []*buildbucketpb.Build); ok {
		r0 = rf(ctx, pred)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*buildbucketpb.Build)
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(context.Context, *buildbucketpb.BuildPredicate) error); ok {
		r1 = rf(ctx, pred)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// NewBuildBucketInterface creates a new instance of BuildBucketInterface. It also registers a cleanup function to assert the mocks expectations.
func NewBuildBucketInterface(t testing.TB) *BuildBucketInterface {
	mock := &BuildBucketInterface{}

	t.Cleanup(func() { mock.AssertExpectations(t) })

	return mock
}
