// Code generated by mockery v1.0.0. DO NOT EDIT.

package mocks

import (
	context "context"
	time "time"

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

	vcsinfo "go.skia.org/infra/go/vcsinfo"
)

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

// ByIndex provides a mock function with given fields: ctx, N
func (_m *VCS) ByIndex(ctx context.Context, N int) (*vcsinfo.LongCommit, error) {
	ret := _m.Called(ctx, N)

	var r0 *vcsinfo.LongCommit
	if rf, ok := ret.Get(0).(func(context.Context, int) *vcsinfo.LongCommit); ok {
		r0 = rf(ctx, N)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*vcsinfo.LongCommit)
		}
	}

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

	return r0, r1
}

// Details provides a mock function with given fields: ctx, hash, includeBranchInfo
func (_m *VCS) Details(ctx context.Context, hash string, includeBranchInfo bool) (*vcsinfo.LongCommit, error) {
	ret := _m.Called(ctx, hash, includeBranchInfo)

	var r0 *vcsinfo.LongCommit
	if rf, ok := ret.Get(0).(func(context.Context, string, bool) *vcsinfo.LongCommit); ok {
		r0 = rf(ctx, hash, includeBranchInfo)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*vcsinfo.LongCommit)
		}
	}

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

	return r0, r1
}

// DetailsMulti provides a mock function with given fields: ctx, hashes, includeBranchInfo
func (_m *VCS) DetailsMulti(ctx context.Context, hashes []string, includeBranchInfo bool) ([]*vcsinfo.LongCommit, error) {
	ret := _m.Called(ctx, hashes, includeBranchInfo)

	var r0 []*vcsinfo.LongCommit
	if rf, ok := ret.Get(0).(func(context.Context, []string, bool) []*vcsinfo.LongCommit); ok {
		r0 = rf(ctx, hashes, includeBranchInfo)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*vcsinfo.LongCommit)
		}
	}

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

	return r0, r1
}

// From provides a mock function with given fields: start
func (_m *VCS) From(start time.Time) []string {
	ret := _m.Called(start)

	var r0 []string
	if rf, ok := ret.Get(0).(func(time.Time) []string); ok {
		r0 = rf(start)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]string)
		}
	}

	return r0
}

// GetFile provides a mock function with given fields: ctx, fileName, commitHash
func (_m *VCS) GetFile(ctx context.Context, fileName string, commitHash string) (string, error) {
	ret := _m.Called(ctx, fileName, commitHash)

	var r0 string
	if rf, ok := ret.Get(0).(func(context.Context, string, string) string); ok {
		r0 = rf(ctx, fileName, commitHash)
	} else {
		r0 = ret.Get(0).(string)
	}

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

	return r0, r1
}

// IndexOf provides a mock function with given fields: ctx, hash
func (_m *VCS) IndexOf(ctx context.Context, hash string) (int, error) {
	ret := _m.Called(ctx, hash)

	var r0 int
	if rf, ok := ret.Get(0).(func(context.Context, string) int); ok {
		r0 = rf(ctx, hash)
	} else {
		r0 = ret.Get(0).(int)
	}

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

	return r0, r1
}

// LastNIndex provides a mock function with given fields: N
func (_m *VCS) LastNIndex(N int) []*vcsinfo.IndexCommit {
	ret := _m.Called(N)

	var r0 []*vcsinfo.IndexCommit
	if rf, ok := ret.Get(0).(func(int) []*vcsinfo.IndexCommit); ok {
		r0 = rf(N)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*vcsinfo.IndexCommit)
		}
	}

	return r0
}

// Range provides a mock function with given fields: begin, end
func (_m *VCS) Range(begin time.Time, end time.Time) []*vcsinfo.IndexCommit {
	ret := _m.Called(begin, end)

	var r0 []*vcsinfo.IndexCommit
	if rf, ok := ret.Get(0).(func(time.Time, time.Time) []*vcsinfo.IndexCommit); ok {
		r0 = rf(begin, end)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]*vcsinfo.IndexCommit)
		}
	}

	return r0
}

// Update provides a mock function with given fields: ctx, pull, allBranches
func (_m *VCS) Update(ctx context.Context, pull bool, allBranches bool) error {
	ret := _m.Called(ctx, pull, allBranches)

	var r0 error
	if rf, ok := ret.Get(0).(func(context.Context, bool, bool) error); ok {
		r0 = rf(ctx, pull, allBranches)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}
