package pkg

import (
	"bufio"
	"bytes"
	"context"
	"go/format"
	"io"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/require"
	"github.com/stretchr/testify/suite"
	mocks "github.com/vektra/mockery/v2/mocks/pkg/fixtures"
	"github.com/vektra/mockery/v2/pkg/config"
)

const pkg = "test"

type GeneratorSuite struct {
	suite.Suite
	parser *Parser
	ctx    context.Context
}

func (s *GeneratorSuite) SetupTest() {
	s.parser = NewParser(nil)
	s.ctx = context.Background()
}

func (s *GeneratorSuite) getInterfaceFromFile(interfacePath, interfaceName string) *Interface {
	if !filepath.IsAbs(interfacePath) {
		interfacePath = getFixturePath(interfacePath)
	}
	s.NoError(
		s.parser.Parse(s.ctx, interfacePath), "The parser is able to parse the given file.",
	)

	s.NoError(
		s.parser.Load(), "The parser is able to load the config.",
	)

	iface, err := s.parser.Find(interfaceName)
	s.Require().NoError(err)
	s.Require().NotNil(iface)
	return iface
}

func (s *GeneratorSuite) getGeneratorWithConfig(
	filepath, interfaceName string, cfg config.Config,
) *Generator {
	return NewGenerator(s.ctx, cfg, s.getInterfaceFromFile(filepath, interfaceName), pkg)
}

func (s *GeneratorSuite) checkGenerationWithConfig(
	filepath, interfaceName string, cfg config.Config, expected string,
) *Generator {
	generator := s.getGeneratorWithConfig(filepath, interfaceName, cfg)
	err := generator.Generate(s.ctx)
	s.NoError(err, "The generator ran without errors.")
	if err != nil {
		return generator
	}

	// Mirror the formatting done by normally done by golang.org/x/tools/imports in Generator.Write.
	//
	// While we could possibly reuse Generator.Write here in addition to Generator.Generate,
	// it would require changing Write's signature to accept custom options, specifically to
	// allow the fragments in preexisting cases. It's assumed that this approximation,
	// just formatting the source, is sufficient for the needs of the current test styles.
	var actual []byte
	actual, fmtErr := format.Source(generator.buf.Bytes())
	s.NoError(fmtErr, "The formatter ran without errors.")

	// Compare lines for easier debugging via testify's slice diff output
	expectedLines := strings.Split(expected, "\n")
	actualLines := strings.Split(string(actual), "\n")

	s.Equal(
		expectedLines, actualLines,
		"The generator produced unexpected output.",
	)

	return generator
}

func (s *GeneratorSuite) getGenerator(
	filepath, interfaceName string, inPackage bool, structName string,
) *Generator {
	return s.getGeneratorWithConfig(filepath, interfaceName, config.Config{
		StructName:     structName,
		InPackage:      inPackage,
		UnrollVariadic: true,
	})
}

func (s *GeneratorSuite) checkGeneration(filepath, interfaceName string, inPackage bool, structName string, expected string) *Generator {
	cfg := config.Config{
		StructName:     structName,
		InPackage:      inPackage,
		UnrollVariadic: true,
	}
	return s.checkGenerationWithConfig(filepath, interfaceName, cfg, expected)
}

func (s *GeneratorSuite) checkPrologueGeneration(
	generator *Generator, expected string,
) {
	generator.GeneratePrologue(ctx, "mocks")
	s.Equal(
		expected, generator.buf.String(),
		"The generator produced an unexpected prologue.",
	)
}

func (s *GeneratorSuite) TestCalculateImport() {
	gp := []string{"a/src", "b/src"}

	s.Equal("c", calculateImport(ctx, gp, "a/src/c"))
	s.Equal("c", calculateImport(ctx, gp, "b/src/c"))
	s.Equal("d/src/c", calculateImport(ctx, gp, "d/src/c"))
}

func (s *GeneratorSuite) TestGenerator() {
	expected := `// Requester is an autogenerated mock type for the Requester type
type Requester struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *Requester) Get(path string) (string, error) {
	ret := _m.Called(path)

	var r0 string
	if rf, ok := ret.Get(0).(func(string) string); ok {
		r0 = rf(path)
	} else {
		r0 = ret.Get(0).(string)
	}

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

	return r0, r1
}

type mockConstructorTestingTNewRequester interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester creates a new instance of Requester. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester(t mockConstructorTestingTNewRequester) *Requester {
	mock := &Requester{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration(testFile, "Requester", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorRequesterWithExpecter() {
	expected := `// Requester is an autogenerated mock type for the Requester type
type Requester struct {
	mock.Mock
}

type Requester_Expecter struct {
	mock *mock.Mock
}

func (_m *Requester) EXPECT() *Requester_Expecter {
	return &Requester_Expecter{mock: &_m.Mock}
}

// Get provides a mock function with given fields: path
func (_m *Requester) Get(path string) (string, error) {
	ret := _m.Called(path)

	var r0 string
	if rf, ok := ret.Get(0).(func(string) string); ok {
		r0 = rf(path)
	} else {
		r0 = ret.Get(0).(string)
	}

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

	return r0, r1
}

// Requester_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get'
type Requester_Get_Call struct {
	*mock.Call
}

// Get is a helper method to define mock.On call
//   - path string
func (_e *Requester_Expecter) Get(path interface{}) *Requester_Get_Call {
	return &Requester_Get_Call{Call: _e.mock.On("Get", path)}
}

func (_c *Requester_Get_Call) Run(run func(path string)) *Requester_Get_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}

func (_c *Requester_Get_Call) Return(_a0 string, _a1 error) *Requester_Get_Call {
	_c.Call.Return(_a0, _a1)
	return _c
}

type mockConstructorTestingTNewRequester interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester creates a new instance of Requester. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester(t mockConstructorTestingTNewRequester) *Requester {
	mock := &Requester{}
	mock.Mock.Test(t)

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

	return mock
}
`

	cfg := config.Config{
		WithExpecter:   true,
		UnrollVariadic: false, // it's okay if the interface doesn't have any variadic method
	}
	s.checkGenerationWithConfig(testFile, "Requester", cfg, expected)
}

func (s *GeneratorSuite) TestGeneratorExpecterComplete() {
	expected := `// Expecter is an autogenerated mock type for the Expecter type
type Expecter struct {
	mock.Mock
}

type Expecter_Expecter struct {
	mock *mock.Mock
}

func (_m *Expecter) EXPECT() *Expecter_Expecter {
	return &Expecter_Expecter{mock: &_m.Mock}
}

// ManyArgsReturns provides a mock function with given fields: str, i
func (_m *Expecter) ManyArgsReturns(str string, i int) ([]string, error) {
	ret := _m.Called(str, i)

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

	var r1 error
	if rf, ok := ret.Get(1).(func(string, int) error); ok {
		r1 = rf(str, i)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// Expecter_ManyArgsReturns_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ManyArgsReturns'
type Expecter_ManyArgsReturns_Call struct {
	*mock.Call
}

// ManyArgsReturns is a helper method to define mock.On call
//   - str string
//   - i int
func (_e *Expecter_Expecter) ManyArgsReturns(str interface{}, i interface{}) *Expecter_ManyArgsReturns_Call {
	return &Expecter_ManyArgsReturns_Call{Call: _e.mock.On("ManyArgsReturns", str, i)}
}

func (_c *Expecter_ManyArgsReturns_Call) Run(run func(str string, i int)) *Expecter_ManyArgsReturns_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string), args[1].(int))
	})
	return _c
}

func (_c *Expecter_ManyArgsReturns_Call) Return(strs []string, err error) *Expecter_ManyArgsReturns_Call {
	_c.Call.Return(strs, err)
	return _c
}

// NoArg provides a mock function with given fields:
func (_m *Expecter) NoArg() string {
	ret := _m.Called()

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

	return r0
}

// Expecter_NoArg_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NoArg'
type Expecter_NoArg_Call struct {
	*mock.Call
}

// NoArg is a helper method to define mock.On call
func (_e *Expecter_Expecter) NoArg() *Expecter_NoArg_Call {
	return &Expecter_NoArg_Call{Call: _e.mock.On("NoArg")}
}

func (_c *Expecter_NoArg_Call) Run(run func()) *Expecter_NoArg_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run()
	})
	return _c
}

func (_c *Expecter_NoArg_Call) Return(_a0 string) *Expecter_NoArg_Call {
	_c.Call.Return(_a0)
	return _c
}

// NoReturn provides a mock function with given fields: str
func (_m *Expecter) NoReturn(str string) {
	_m.Called(str)
}

// Expecter_NoReturn_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'NoReturn'
type Expecter_NoReturn_Call struct {
	*mock.Call
}

// NoReturn is a helper method to define mock.On call
//   - str string
func (_e *Expecter_Expecter) NoReturn(str interface{}) *Expecter_NoReturn_Call {
	return &Expecter_NoReturn_Call{Call: _e.mock.On("NoReturn", str)}
}

func (_c *Expecter_NoReturn_Call) Run(run func(str string)) *Expecter_NoReturn_Call {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(string))
	})
	return _c
}

func (_c *Expecter_NoReturn_Call) Return() *Expecter_NoReturn_Call {
	_c.Call.Return()
	return _c
}

// Variadic provides a mock function with given fields: ints
func (_m *Expecter) Variadic(ints ...int) error {
	_va := make([]interface{}, len(ints))
	for _i := range ints {
		_va[_i] = ints[_i]
	}
	var _ca []interface{}
	_ca = append(_ca, _va...)
	ret := _m.Called(_ca...)

	var r0 error
	if rf, ok := ret.Get(0).(func(...int) error); ok {
		r0 = rf(ints...)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// Expecter_Variadic_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Variadic'
type Expecter_Variadic_Call struct {
	*mock.Call
}

// Variadic is a helper method to define mock.On call
//   - ints ...int
func (_e *Expecter_Expecter) Variadic(ints ...interface{}) *Expecter_Variadic_Call {
	return &Expecter_Variadic_Call{Call: _e.mock.On("Variadic",
		append([]interface{}{}, ints...)...)}
}

func (_c *Expecter_Variadic_Call) Run(run func(ints ...int)) *Expecter_Variadic_Call {
	_c.Call.Run(func(args mock.Arguments) {
		variadicArgs := make([]int, len(args)-0)
		for i, a := range args[0:] {
			if a != nil {
				variadicArgs[i] = a.(int)
			}
		}
		run(variadicArgs...)
	})
	return _c
}

func (_c *Expecter_Variadic_Call) Return(_a0 error) *Expecter_Variadic_Call {
	_c.Call.Return(_a0)
	return _c
}

// VariadicMany provides a mock function with given fields: i, a, intfs
func (_m *Expecter) VariadicMany(i int, a string, intfs ...interface{}) error {
	var _ca []interface{}
	_ca = append(_ca, i, a)
	_ca = append(_ca, intfs...)
	ret := _m.Called(_ca...)

	var r0 error
	if rf, ok := ret.Get(0).(func(int, string, ...interface{}) error); ok {
		r0 = rf(i, a, intfs...)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

// Expecter_VariadicMany_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'VariadicMany'
type Expecter_VariadicMany_Call struct {
	*mock.Call
}

// VariadicMany is a helper method to define mock.On call
//   - i int
//   - a string
//   - intfs ...interface{}
func (_e *Expecter_Expecter) VariadicMany(i interface{}, a interface{}, intfs ...interface{}) *Expecter_VariadicMany_Call {
	return &Expecter_VariadicMany_Call{Call: _e.mock.On("VariadicMany",
		append([]interface{}{i, a}, intfs...)...)}
}

func (_c *Expecter_VariadicMany_Call) Run(run func(i int, a string, intfs ...interface{})) *Expecter_VariadicMany_Call {
	_c.Call.Run(func(args mock.Arguments) {
		variadicArgs := make([]interface{}, len(args)-2)
		for i, a := range args[2:] {
			if a != nil {
				variadicArgs[i] = a.(interface{})
			}
		}
		run(args[0].(int), args[1].(string), variadicArgs...)
	})
	return _c
}

func (_c *Expecter_VariadicMany_Call) Return(_a0 error) *Expecter_VariadicMany_Call {
	_c.Call.Return(_a0)
	return _c
}

type mockConstructorTestingTNewExpecter interface {
	mock.TestingT
	Cleanup(func())
}

// NewExpecter creates a new instance of Expecter. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewExpecter(t mockConstructorTestingTNewExpecter) *Expecter {
	mock := &Expecter{}
	mock.Mock.Test(t)

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

	return mock
}
`

	cfg := config.Config{
		StructName:     "Expecter",
		WithExpecter:   true,
		UnrollVariadic: true,
	}
	s.checkGenerationWithConfig("expecter.go", "Expecter", cfg, expected)
}

func (s *GeneratorSuite) TestGeneratorExpecterFailsWithoutUnrolledVariadic() {
	cfg := config.Config{
		WithExpecter:   true,
		UnrollVariadic: false,
	}
	gen := s.getGeneratorWithConfig("expecter.go", "Expecter", cfg)
	err := gen.Generate(s.ctx)
	s.Error(err)
	s.Contains(err.Error(), "cannot generate a valid expecter for variadic method with unroll-variadic=false")
}

func (s *GeneratorSuite) TestGeneratorFunction() {
	expected := `// SendFunc is an autogenerated mock type for the SendFunc type
type SendFunc struct {
	mock.Mock
}

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

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

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

	return r0, r1
}

type mockConstructorTestingTNewSendFunc interface {
	mock.TestingT
	Cleanup(func())
}

// NewSendFunc creates a new instance of SendFunc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewSendFunc(t mockConstructorTestingTNewSendFunc) *SendFunc {
	mock := &SendFunc{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("function.go", "SendFunc", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorSingleReturn() {
	expected := `// Requester2 is an autogenerated mock type for the Requester2 type
type Requester2 struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *Requester2) Get(path string) error {
	ret := _m.Called(path)

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(path)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewRequester2 interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester2 creates a new instance of Requester2. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester2(t mockConstructorTestingTNewRequester2) *Requester2 {
	mock := &Requester2{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration(testFile2, "Requester2", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorNoArguments() {
	expected := `// Requester3 is an autogenerated mock type for the Requester3 type
type Requester3 struct {
	mock.Mock
}

// Get provides a mock function with given fields:
func (_m *Requester3) Get() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewRequester3 interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester3 creates a new instance of Requester3. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester3(t mockConstructorTestingTNewRequester3) *Requester3 {
	mock := &Requester3{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester3.go", "Requester3", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorNoNothing() {
	expected := `// Requester4 is an autogenerated mock type for the Requester4 type
type Requester4 struct {
	mock.Mock
}

// Get provides a mock function with given fields:
func (_m *Requester4) Get() {
	_m.Called()
}

type mockConstructorTestingTNewRequester4 interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester4 creates a new instance of Requester4. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester4(t mockConstructorTestingTNewRequester4) *Requester4 {
	mock := &Requester4{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester4.go", "Requester4", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorUnexported() {
	expected := `// mockRequester_unexported is an autogenerated mock type for the requester_unexported type
type mockRequester_unexported struct {
	mock.Mock
}

// Get provides a mock function with given fields:
func (_m *mockRequester_unexported) Get() {
	_m.Called()
}

type mockConstructorTestingTnewMockRequester_unexported interface {
	mock.TestingT
	Cleanup(func())
}

// newMockRequester_unexported creates a new instance of mockRequester_unexported. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func newMockRequester_unexported(t mockConstructorTestingTnewMockRequester_unexported) *mockRequester_unexported {
	mock := &mockRequester_unexported{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_unexported.go", "requester_unexported", true, "", expected)
}

func (s *GeneratorSuite) TestGeneratorExportedOnFlag() {
	expected := `// Mockrequester_unexported is an autogenerated mock type for the requester_unexported type
type Mockrequester_unexported struct {
	mock.Mock
}

// Get provides a mock function with given fields:
func (_m *Mockrequester_unexported) Get() {
	_m.Called()
}

type mockConstructorTestingTNewMockrequester_unexported interface {
	mock.TestingT
	Cleanup(func())
}

// NewMockrequester_unexported creates a new instance of Mockrequester_unexported. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockrequester_unexported(t mockConstructorTestingTNewMockrequester_unexported) *Mockrequester_unexported {
	mock := &Mockrequester_unexported{}
	mock.Mock.Test(t)

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

	return mock
}
`
	generator := NewGenerator(
		s.ctx, config.Config{
			StructName: "",
			InPackage:  true,
			Exported:   true,
		}, s.getInterfaceFromFile("requester_unexported.go", "requester_unexported"), pkg,
	)
	s.NoError(generator.Generate(s.ctx), "The generator ran without errors.")

	var actual []byte
	actual, fmtErr := format.Source(generator.buf.Bytes())
	s.NoError(fmtErr, "The formatter ran without errors.")

	expectedLines := strings.Split(expected, "\n")
	actualLines := strings.Split(string(actual), "\n")

	s.Equal(
		expectedLines, actualLines,
		"The generator produced unexpected output.",
	)
}

func (s *GeneratorSuite) TestGeneratorExportedOnFlagNotInPackage() {
	expected := `// Requester_unexported is an autogenerated mock type for the requester_unexported type
type Requester_unexported struct {
	mock.Mock
}

// Get provides a mock function with given fields:
func (_m *Requester_unexported) Get() {
	_m.Called()
}

type mockConstructorTestingTNewRequester_unexported interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester_unexported creates a new instance of Requester_unexported. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester_unexported(t mockConstructorTestingTNewRequester_unexported) *Requester_unexported {
	mock := &Requester_unexported{}
	mock.Mock.Test(t)

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

	return mock
}
`
	generator := NewGenerator(
		s.ctx, config.Config{
			StructName: "",
			InPackage:  false,
			Exported:   true,
		}, s.getInterfaceFromFile("requester_unexported.go", "requester_unexported"), pkg,
	)
	s.NoError(generator.Generate(s.ctx), "The generator ran without errors.")

	var actual []byte
	actual, fmtErr := format.Source(generator.buf.Bytes())
	s.NoError(fmtErr, "The formatter ran without errors.")

	expectedLines := strings.Split(expected, "\n")
	actualLines := strings.Split(string(actual), "\n")

	s.Equal(
		expectedLines, actualLines,
		"The generator produced unexpected output.",
	)
}

func (s *GeneratorSuite) TestGeneratorPrologue() {
	generator := s.getGenerator(testFile, "Requester", false, "")
	expected := `package mocks

import mock "github.com/stretchr/testify/mock"
import test "github.com/vektra/mockery/v2/pkg/fixtures"

`
	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestGeneratorPrologueWithImports() {
	generator := s.getGenerator("requester_ns.go", "RequesterNS", false, "")
	expected := `package mocks

import http "net/http"
import mock "github.com/stretchr/testify/mock"
import test "github.com/vektra/mockery/v2/pkg/fixtures"

`
	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestGeneratorPrologueWithMultipleImportsSameName() {
	generator := s.getGenerator("same_name_imports.go", "Example", false, "")

	expected := `package mocks

import fixtureshttp "github.com/vektra/mockery/v2/pkg/fixtures/http"
import http "net/http"
import mock "github.com/stretchr/testify/mock"
import test "github.com/vektra/mockery/v2/pkg/fixtures"

`
	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestGeneratorPrologueNote() {
	generator := s.getGenerator(testFile, "Requester", false, "")
	generator.GeneratePrologueNote("A\\nB")

	expected := `// Code generated by mockery v0.0.0-dev. DO NOT EDIT.

// A
// B

`

	s.Equal(expected, generator.buf.String())
}

func (s *GeneratorSuite) TestGeneratorBoilerplate() {
	generator := s.getGenerator(testFile, "Requester", false, "")
	generator.GenerateBoilerplate("/*\n    BOILERPLATE\n*/\n")

	expected := `/*
    BOILERPLATE
*/

`

	s.Equal(expected, generator.buf.String())
}

func (s *GeneratorSuite) TestGeneratorPrologueNoteNoVersionString() {
	generator := s.getGenerator(testFile, "Requester", false, "")
	generator.Config.DisableVersionString = true
	generator.GeneratePrologueNote("A\\nB")

	expected := `// Code generated by mockery. DO NOT EDIT.

// A
// B

`

	s.Equal(expected, generator.buf.String())
}

func (s *GeneratorSuite) TestVersionOnCorrectLine() {
	gen := s.getGenerator(testFile, "Requester", false, "")

	// Run everything that is ran by the GeneratorVisitor
	gen.GeneratePrologueNote("A\\nB")
	gen.GeneratePrologue(s.ctx, pkg)
	err := gen.Generate(s.ctx)

	require.NoError(s.T(), err)
	scan := bufio.NewScanner(&gen.buf)
	s.Contains("Code generated by", scan.Text())
}

func (s *GeneratorSuite) TestGeneratorChecksInterfacesForNilable() {
	expected := `// RequesterIface is an autogenerated mock type for the RequesterIface type
type RequesterIface struct {
	mock.Mock
}

// Get provides a mock function with given fields:
func (_m *RequesterIface) Get() io.Reader {
	ret := _m.Called()

	var r0 io.Reader
	if rf, ok := ret.Get(0).(func() io.Reader); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(io.Reader)
		}
	}

	return r0
}

type mockConstructorTestingTNewRequesterIface interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterIface creates a new instance of RequesterIface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterIface(t mockConstructorTestingTNewRequesterIface) *RequesterIface {
	mock := &RequesterIface{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_iface.go", "RequesterIface", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorPointers() {
	expected := `// RequesterPtr is an autogenerated mock type for the RequesterPtr type
type RequesterPtr struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *RequesterPtr) Get(path string) (*string, error) {
	ret := _m.Called(path)

	var r0 *string
	if rf, ok := ret.Get(0).(func(string) *string); ok {
		r0 = rf(path)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*string)
		}
	}

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

	return r0, r1
}

type mockConstructorTestingTNewRequesterPtr interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterPtr creates a new instance of RequesterPtr. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterPtr(t mockConstructorTestingTNewRequesterPtr) *RequesterPtr {
	mock := &RequesterPtr{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_ptr.go", "RequesterPtr", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorSlice() {
	expected := `// RequesterSlice is an autogenerated mock type for the RequesterSlice type
type RequesterSlice struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *RequesterSlice) Get(path string) ([]string, error) {
	ret := _m.Called(path)

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

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

	return r0, r1
}

type mockConstructorTestingTNewRequesterSlice interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterSlice creates a new instance of RequesterSlice. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterSlice(t mockConstructorTestingTNewRequesterSlice) *RequesterSlice {
	mock := &RequesterSlice{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_slice.go", "RequesterSlice", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorArrayLiteralLen() {
	expected := `// RequesterArray is an autogenerated mock type for the RequesterArray type
type RequesterArray struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *RequesterArray) Get(path string) ([2]string, error) {
	ret := _m.Called(path)

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

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

	return r0, r1
}

type mockConstructorTestingTNewRequesterArray interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterArray creates a new instance of RequesterArray. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterArray(t mockConstructorTestingTNewRequesterArray) *RequesterArray {
	mock := &RequesterArray{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_array.go", "RequesterArray", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorNamespacedTypes() {
	expected := `// RequesterNS is an autogenerated mock type for the RequesterNS type
type RequesterNS struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *RequesterNS) Get(path string) (http.Response, error) {
	ret := _m.Called(path)

	var r0 http.Response
	if rf, ok := ret.Get(0).(func(string) http.Response); ok {
		r0 = rf(path)
	} else {
		r0 = ret.Get(0).(http.Response)
	}

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

	return r0, r1
}

type mockConstructorTestingTNewRequesterNS interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterNS creates a new instance of RequesterNS. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterNS(t mockConstructorTestingTNewRequesterNS) *RequesterNS {
	mock := &RequesterNS{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_ns.go", "RequesterNS", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWhereArgumentNameConflictsWithImport() {
	expected := `// RequesterArgSameAsImport is an autogenerated mock type for the RequesterArgSameAsImport type
type RequesterArgSameAsImport struct {
	mock.Mock
}

// Get provides a mock function with given fields: _a0
func (_m *RequesterArgSameAsImport) Get(_a0 string) *json.RawMessage {
	ret := _m.Called(_a0)

	var r0 *json.RawMessage
	if rf, ok := ret.Get(0).(func(string) *json.RawMessage); ok {
		r0 = rf(_a0)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*json.RawMessage)
		}
	}

	return r0
}

type mockConstructorTestingTNewRequesterArgSameAsImport interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterArgSameAsImport creates a new instance of RequesterArgSameAsImport. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterArgSameAsImport(t mockConstructorTestingTNewRequesterArgSameAsImport) *RequesterArgSameAsImport {
	mock := &RequesterArgSameAsImport{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_arg_same_as_import.go", "RequesterArgSameAsImport", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWhereArgumentNameConflictsWithNamedImport() {
	expected := `// RequesterArgSameAsNamedImport is an autogenerated mock type for the RequesterArgSameAsNamedImport type
type RequesterArgSameAsNamedImport struct {
	mock.Mock
}

// Get provides a mock function with given fields: _a0
func (_m *RequesterArgSameAsNamedImport) Get(_a0 string) *json.RawMessage {
	ret := _m.Called(_a0)

	var r0 *json.RawMessage
	if rf, ok := ret.Get(0).(func(string) *json.RawMessage); ok {
		r0 = rf(_a0)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(*json.RawMessage)
		}
	}

	return r0
}

type mockConstructorTestingTNewRequesterArgSameAsNamedImport interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterArgSameAsNamedImport creates a new instance of RequesterArgSameAsNamedImport. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterArgSameAsNamedImport(t mockConstructorTestingTNewRequesterArgSameAsNamedImport) *RequesterArgSameAsNamedImport {
	mock := &RequesterArgSameAsNamedImport{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_arg_same_as_named_import.go", "RequesterArgSameAsNamedImport", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWhereArgumentNameConflictsWithPackage() {
	expected := `// RequesterArgSameAsPkg is an autogenerated mock type for the RequesterArgSameAsPkg type
type RequesterArgSameAsPkg struct {
	mock.Mock
}

// Get provides a mock function with given fields: _a0
func (_m *RequesterArgSameAsPkg) Get(_a0 string) {
	_m.Called(_a0)
}

type mockConstructorTestingTNewRequesterArgSameAsPkg interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterArgSameAsPkg creates a new instance of RequesterArgSameAsPkg. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterArgSameAsPkg(t mockConstructorTestingTNewRequesterArgSameAsPkg) *RequesterArgSameAsPkg {
	mock := &RequesterArgSameAsPkg{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_arg_same_as_pkg.go", "RequesterArgSameAsPkg", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorHavingNoNamesOnArguments() {
	expected := `// KeyManager is an autogenerated mock type for the KeyManager type
type KeyManager struct {
	mock.Mock
}

// GetKey provides a mock function with given fields: _a0, _a1
func (_m *KeyManager) GetKey(_a0 string, _a1 uint16) ([]byte, *test.Err) {
	ret := _m.Called(_a0, _a1)

	var r0 []byte
	if rf, ok := ret.Get(0).(func(string, uint16) []byte); ok {
		r0 = rf(_a0, _a1)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).([]byte)
		}
	}

	var r1 *test.Err
	if rf, ok := ret.Get(1).(func(string, uint16) *test.Err); ok {
		r1 = rf(_a0, _a1)
	} else {
		if ret.Get(1) != nil {
			r1 = ret.Get(1).(*test.Err)
		}
	}

	return r0, r1
}

type mockConstructorTestingTNewKeyManager interface {
	mock.TestingT
	Cleanup(func())
}

// NewKeyManager creates a new instance of KeyManager. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewKeyManager(t mockConstructorTestingTNewKeyManager) *KeyManager {
	mock := &KeyManager{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("custom_error.go", "KeyManager", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorElidedType() {
	expected := `// RequesterElided is an autogenerated mock type for the RequesterElided type
type RequesterElided struct {
	mock.Mock
}

// Get provides a mock function with given fields: path, url
func (_m *RequesterElided) Get(path string, url string) error {
	ret := _m.Called(path, url)

	var r0 error
	if rf, ok := ret.Get(0).(func(string, string) error); ok {
		r0 = rf(path, url)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewRequesterElided interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterElided creates a new instance of RequesterElided. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterElided(t mockConstructorTestingTNewRequesterElided) *RequesterElided {
	mock := &RequesterElided{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_elided.go", "RequesterElided", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorReturnElidedType() {
	expected := `// RequesterReturnElided is an autogenerated mock type for the RequesterReturnElided type
type RequesterReturnElided struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *RequesterReturnElided) Get(path string) (int, int, int, error) {
	ret := _m.Called(path)

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

	var r1 int
	if rf, ok := ret.Get(1).(func(string) int); ok {
		r1 = rf(path)
	} else {
		r1 = ret.Get(1).(int)
	}

	var r2 int
	if rf, ok := ret.Get(2).(func(string) int); ok {
		r2 = rf(path)
	} else {
		r2 = ret.Get(2).(int)
	}

	var r3 error
	if rf, ok := ret.Get(3).(func(string) error); ok {
		r3 = rf(path)
	} else {
		r3 = ret.Error(3)
	}

	return r0, r1, r2, r3
}

type mockConstructorTestingTNewRequesterReturnElided interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterReturnElided creates a new instance of RequesterReturnElided. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterReturnElided(t mockConstructorTestingTNewRequesterReturnElided) *RequesterReturnElided {
	mock := &RequesterReturnElided{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("requester_ret_elided.go", "RequesterReturnElided", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorVariadicArgs() {
	expectedBytes, err := os.ReadFile(getMocksPath("RequesterVariadic.go"))
	s.NoError(err)
	expected := string(expectedBytes)
	expected = expected[strings.Index(expected, "// RequesterVariadic is"):]
	s.checkGeneration("requester_variadic.go", "RequesterVariadic", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorVariadicArgsAsOneArg() {
	expectedBytes, err := os.ReadFile(getMocksPath("RequesterVariadicOneArgument.go"))
	s.NoError(err)
	expected := string(expectedBytes)
	expected = expected[strings.Index(expected, "// RequesterVariadicOneArgument is"):]
	generator := NewGenerator(
		s.ctx, config.Config{
			StructName:     "RequesterVariadicOneArgument",
			InPackage:      true,
			UnrollVariadic: false,
		}, s.getInterfaceFromFile("requester_variadic.go", "RequesterVariadic"), pkg,
	)
	s.NoError(generator.Generate(s.ctx), "The generator ran without errors.")

	var actual []byte
	actual, fmtErr := format.Source(generator.buf.Bytes())
	s.NoError(fmtErr, "The formatter ran without errors.")

	expectedLines := strings.Split(expected, "\n")
	actualLines := strings.Split(string(actual), "\n")

	s.Equal(
		expectedLines, actualLines,
		"The generator produced unexpected output.",
	)
}

func TestRequesterVariadicOneArgument(t *testing.T) {
	t.Run("Get \"1\", \"2\", \"3\"", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []string{"1", "2", "3"}
		m.On("Get", args).Return(true).Once()
		res := m.Get(args...)
		assert.True(t, res)
		m.AssertExpectations(t)
	})

	t.Run("Get mock.Anything", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []string{"1", "2", "3"}
		m.On("Get", mock.Anything).Return(true).Once()
		res := m.Get(args...)
		assert.True(t, res)
		m.AssertExpectations(t)
	})

	t.Run("Get no arguments", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		m.On("Get", []string(nil)).Return(true).Once()
		res := m.Get()
		assert.True(t, res)
		m.AssertExpectations(t)
	})

	t.Run("MultiWriteToFile strings builders", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []io.Writer{&strings.Builder{}, &strings.Builder{}}
		expected := "res"
		filename := "testFilename"
		m.On("MultiWriteToFile", filename, args).Return(expected).Once()
		res := m.MultiWriteToFile(filename, args...)
		assert.Equal(t, expected, res)
		m.AssertExpectations(t)
	})

	t.Run("MultiWriteToFile mock.Anything", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []io.Writer{&strings.Builder{}, &strings.Builder{}}
		expected := "res"
		filename := "testFilename"
		m.On("MultiWriteToFile", filename, mock.Anything).Return(expected).Once()
		res := m.MultiWriteToFile(filename, args...)
		assert.Equal(t, expected, res)
		m.AssertExpectations(t)
	})

	t.Run("OneInterface \"1\", \"2\", \"3\"", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []interface{}{"1", "2", "3"}
		m.On("OneInterface", args).Return(true).Once()
		res := m.OneInterface(args...)
		assert.True(t, res)
		m.AssertExpectations(t)
	})

	t.Run("OneInterface mock.Anything", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []interface{}{"1", "2", "3"}
		m.On("OneInterface", mock.Anything).Return(true).Once()
		res := m.OneInterface(args...)
		assert.True(t, res)
		m.AssertExpectations(t)
	})

	t.Run("Sprintf strings builders", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []interface{}{&strings.Builder{}, &strings.Builder{}}
		expected := "res"
		filename := "testFilename"
		m.On("Sprintf", filename, args).Return(expected).Once()
		res := m.Sprintf(filename, args...)
		assert.Equal(t, expected, res)
		m.AssertExpectations(t)
	})

	t.Run("Sprintf mock.Anything", func(t *testing.T) {
		m := mocks.RequesterVariadicOneArgument{}
		args := []interface{}{&strings.Builder{}, &strings.Builder{}}
		expected := "res"
		filename := "testFilename"
		m.On("Sprintf", filename, mock.Anything).Return(expected).Once()
		res := m.Sprintf(filename, args...)
		assert.Equal(t, expected, res)
		m.AssertExpectations(t)
	})
}

func (s *GeneratorSuite) TestGeneratorArgumentIsFuncType() {
	expected := `// Fooer is an autogenerated mock type for the Fooer type
type Fooer struct {
	mock.Mock
}

// Bar provides a mock function with given fields: f
func (_m *Fooer) Bar(f func([]int)) {
	_m.Called(f)
}

// Baz provides a mock function with given fields: path
func (_m *Fooer) Baz(path string) func(string) string {
	ret := _m.Called(path)

	var r0 func(string) string
	if rf, ok := ret.Get(0).(func(string) func(string) string); ok {
		r0 = rf(path)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(func(string) string)
		}
	}

	return r0
}

// Foo provides a mock function with given fields: f
func (_m *Fooer) Foo(f func(string) string) error {
	ret := _m.Called(f)

	var r0 error
	if rf, ok := ret.Get(0).(func(func(string) string) error); ok {
		r0 = rf(f)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewFooer interface {
	mock.TestingT
	Cleanup(func())
}

// NewFooer creates a new instance of Fooer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewFooer(t mockConstructorTestingTNewFooer) *Fooer {
	mock := &Fooer{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("func_type.go", "Fooer", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorChanType() {
	expected := `// AsyncProducer is an autogenerated mock type for the AsyncProducer type
type AsyncProducer struct {
	mock.Mock
}

// Input provides a mock function with given fields:
func (_m *AsyncProducer) Input() chan<- bool {
	ret := _m.Called()

	var r0 chan<- bool
	if rf, ok := ret.Get(0).(func() chan<- bool); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(chan<- bool)
		}
	}

	return r0
}

// Output provides a mock function with given fields:
func (_m *AsyncProducer) Output() <-chan bool {
	ret := _m.Called()

	var r0 <-chan bool
	if rf, ok := ret.Get(0).(func() <-chan bool); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(<-chan bool)
		}
	}

	return r0
}

// Whatever provides a mock function with given fields:
func (_m *AsyncProducer) Whatever() chan bool {
	ret := _m.Called()

	var r0 chan bool
	if rf, ok := ret.Get(0).(func() chan bool); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(chan bool)
		}
	}

	return r0
}

type mockConstructorTestingTNewAsyncProducer interface {
	mock.TestingT
	Cleanup(func())
}

// NewAsyncProducer creates a new instance of AsyncProducer. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewAsyncProducer(t mockConstructorTestingTNewAsyncProducer) *AsyncProducer {
	mock := &AsyncProducer{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("async.go", "AsyncProducer", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorFromImport() {
	expected := `// MyReader is an autogenerated mock type for the MyReader type
type MyReader struct {
	mock.Mock
}

// Read provides a mock function with given fields: p
func (_m *MyReader) Read(p []byte) (int, error) {
	ret := _m.Called(p)

	var r0 int
	if rf, ok := ret.Get(0).(func([]byte) int); ok {
		r0 = rf(p)
	} else {
		r0 = ret.Get(0).(int)
	}

	var r1 error
	if rf, ok := ret.Get(1).(func([]byte) error); ok {
		r1 = rf(p)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

type mockConstructorTestingTNewMyReader interface {
	mock.TestingT
	Cleanup(func())
}

// NewMyReader creates a new instance of MyReader. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMyReader(t mockConstructorTestingTNewMyReader) *MyReader {
	mock := &MyReader{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("io_import.go", "MyReader", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorComplexChanFromConsul() {
	expected := `// ConsulLock is an autogenerated mock type for the ConsulLock type
type ConsulLock struct {
	mock.Mock
}

// Lock provides a mock function with given fields: _a0
func (_m *ConsulLock) Lock(_a0 <-chan struct{}) (<-chan struct{}, error) {
	ret := _m.Called(_a0)

	var r0 <-chan struct{}
	if rf, ok := ret.Get(0).(func(<-chan struct{}) <-chan struct{}); ok {
		r0 = rf(_a0)
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(<-chan struct{})
		}
	}

	var r1 error
	if rf, ok := ret.Get(1).(func(<-chan struct{}) error); ok {
		r1 = rf(_a0)
	} else {
		r1 = ret.Error(1)
	}

	return r0, r1
}

// Unlock provides a mock function with given fields:
func (_m *ConsulLock) Unlock() error {
	ret := _m.Called()

	var r0 error
	if rf, ok := ret.Get(0).(func() error); ok {
		r0 = rf()
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewConsulLock interface {
	mock.TestingT
	Cleanup(func())
}

// NewConsulLock creates a new instance of ConsulLock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewConsulLock(t mockConstructorTestingTNewConsulLock) *ConsulLock {
	mock := &ConsulLock{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("consul.go", "ConsulLock", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorForEmptyInterface() {
	expected := `// Blank is an autogenerated mock type for the Blank type
type Blank struct {
	mock.Mock
}

// Create provides a mock function with given fields: x
func (_m *Blank) Create(x interface{}) error {
	ret := _m.Called(x)

	var r0 error
	if rf, ok := ret.Get(0).(func(interface{}) error); ok {
		r0 = rf(x)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewBlank interface {
	mock.TestingT
	Cleanup(func())
}

// NewBlank creates a new instance of Blank. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewBlank(t mockConstructorTestingTNewBlank) *Blank {
	mock := &Blank{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("empty_interface.go", "Blank", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorArgumentIsMapFunc() {
	expected := `// MapFunc is an autogenerated mock type for the MapFunc type
type MapFunc struct {
	mock.Mock
}

// Get provides a mock function with given fields: m
func (_m *MapFunc) Get(m map[string]func(string) string) error {
	ret := _m.Called(m)

	var r0 error
	if rf, ok := ret.Get(0).(func(map[string]func(string) string) error); ok {
		r0 = rf(m)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewMapFunc interface {
	mock.TestingT
	Cleanup(func())
}

// NewMapFunc creates a new instance of MapFunc. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMapFunc(t mockConstructorTestingTNewMapFunc) *MapFunc {
	mock := &MapFunc{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("map_func.go", "MapFunc", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorForMethodUsingInterface() {
	expected := `// UsesOtherPkgIface is an autogenerated mock type for the UsesOtherPkgIface type
type UsesOtherPkgIface struct {
	mock.Mock
}

// DoSomethingElse provides a mock function with given fields: obj
func (_m *UsesOtherPkgIface) DoSomethingElse(obj test.Sibling) {
	_m.Called(obj)
}

type mockConstructorTestingTNewUsesOtherPkgIface interface {
	mock.TestingT
	Cleanup(func())
}

// NewUsesOtherPkgIface creates a new instance of UsesOtherPkgIface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewUsesOtherPkgIface(t mockConstructorTestingTNewUsesOtherPkgIface) *UsesOtherPkgIface {
	mock := &UsesOtherPkgIface{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("mock_method_uses_pkg_iface.go", "UsesOtherPkgIface", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorForMethodUsingInterfaceInPackage() {
	expected := `// MockUsesOtherPkgIface is an autogenerated mock type for the UsesOtherPkgIface type
type MockUsesOtherPkgIface struct {
	mock.Mock
}

// DoSomethingElse provides a mock function with given fields: obj
func (_m *MockUsesOtherPkgIface) DoSomethingElse(obj Sibling) {
	_m.Called(obj)
}

type mockConstructorTestingTNewMockUsesOtherPkgIface interface {
	mock.TestingT
	Cleanup(func())
}

// NewMockUsesOtherPkgIface creates a new instance of MockUsesOtherPkgIface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockUsesOtherPkgIface(t mockConstructorTestingTNewMockUsesOtherPkgIface) *MockUsesOtherPkgIface {
	mock := &MockUsesOtherPkgIface{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("mock_method_uses_pkg_iface.go", "UsesOtherPkgIface", true, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWithAliasing() {
	expected := `// Example is an autogenerated mock type for the Example type
type Example struct {
	mock.Mock
}

// A provides a mock function with given fields:
func (_m *Example) A() http.Flusher {
	ret := _m.Called()

	var r0 http.Flusher
	if rf, ok := ret.Get(0).(func() http.Flusher); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(http.Flusher)
		}
	}

	return r0
}

// B provides a mock function with given fields: _a0
func (_m *Example) B(_a0 string) fixtureshttp.MyStruct {
	ret := _m.Called(_a0)

	var r0 fixtureshttp.MyStruct
	if rf, ok := ret.Get(0).(func(string) fixtureshttp.MyStruct); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(fixtureshttp.MyStruct)
	}

	return r0
}

type mockConstructorTestingTNewExample interface {
	mock.TestingT
	Cleanup(func())
}

// NewExample creates a new instance of Example. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewExample(t mockConstructorTestingTNewExample) *Example {
	mock := &Example{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("same_name_imports.go", "Example", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWithImportSameAsLocalPackageInpkgNoCycle() {
	iface := s.getInterfaceFromFile("imports_same_as_package.go", "ImportsSameAsPackage")
	pkg := iface.QualifiedName
	gen := NewGenerator(s.ctx, config.Config{
		InPackage: true,
	}, iface, pkg)
	gen.GeneratePrologue(s.ctx, pkg)
	s.NotContains(gen.buf.String(), `import test "github.com/vektra/mockery/v2/pkg/fixtures/test"`)
}

func (s *GeneratorSuite) TestMapToInterface() {
	expected := `// MapToInterface is an autogenerated mock type for the MapToInterface type
type MapToInterface struct {
	mock.Mock
}

// Foo provides a mock function with given fields: arg1
func (_m *MapToInterface) Foo(arg1 ...map[string]interface{}) {
	_va := make([]interface{}, len(arg1))
	for _i := range arg1 {
		_va[_i] = arg1[_i]
	}
	var _ca []interface{}
	_ca = append(_ca, _va...)
	_m.Called(_ca...)
}

type mockConstructorTestingTNewMapToInterface interface {
	mock.TestingT
	Cleanup(func())
}

// NewMapToInterface creates a new instance of MapToInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMapToInterface(t mockConstructorTestingTNewMapToInterface) *MapToInterface {
	mock := &MapToInterface{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("MapToInterface.go", "MapToInterface", false, "", expected)

}

func (s *GeneratorSuite) TestGeneratorFunctionArgsNamesCollision() {
	expected := `// FuncArgsCollision is an autogenerated mock type for the FuncArgsCollision type
type FuncArgsCollision struct {
	mock.Mock
}

// Foo provides a mock function with given fields: ret
func (_m *FuncArgsCollision) Foo(ret interface{}) error {
	ret_1 := _m.Called(ret)

	var r0 error
	if rf, ok := ret_1.Get(0).(func(interface{}) error); ok {
		r0 = rf(ret)
	} else {
		r0 = ret_1.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewFuncArgsCollision interface {
	mock.TestingT
	Cleanup(func())
}

// NewFuncArgsCollision creates a new instance of FuncArgsCollision. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewFuncArgsCollision(t mockConstructorTestingTNewFuncArgsCollision) *FuncArgsCollision {
	mock := &FuncArgsCollision{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("func_args_collision.go", "FuncArgsCollision", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWithImportSameAsLocalPackage() {
	expected := `// ImportsSameAsPackage is an autogenerated mock type for the ImportsSameAsPackage type
type ImportsSameAsPackage struct {
	mock.Mock
}

// A provides a mock function with given fields:
func (_m *ImportsSameAsPackage) A() test.B {
	ret := _m.Called()

	var r0 test.B
	if rf, ok := ret.Get(0).(func() test.B); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(test.B)
	}

	return r0
}

// B provides a mock function with given fields:
func (_m *ImportsSameAsPackage) B() fixtures.KeyManager {
	ret := _m.Called()

	var r0 fixtures.KeyManager
	if rf, ok := ret.Get(0).(func() fixtures.KeyManager); ok {
		r0 = rf()
	} else {
		if ret.Get(0) != nil {
			r0 = ret.Get(0).(fixtures.KeyManager)
		}
	}

	return r0
}

// C provides a mock function with given fields: _a0
func (_m *ImportsSameAsPackage) C(_a0 fixtures.C) {
	_m.Called(_a0)
}

type mockConstructorTestingTNewImportsSameAsPackage interface {
	mock.TestingT
	Cleanup(func())
}

// NewImportsSameAsPackage creates a new instance of ImportsSameAsPackage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewImportsSameAsPackage(t mockConstructorTestingTNewImportsSameAsPackage) *ImportsSameAsPackage {
	mock := &ImportsSameAsPackage{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("imports_same_as_package.go", "ImportsSameAsPackage", false, "", expected)
}

func (s *GeneratorSuite) TestGeneratorWithUnsafePointer() {
	expected := `// UnsafeInterface is an autogenerated mock type for the UnsafeInterface type
type UnsafeInterface struct {
	mock.Mock
}

// Do provides a mock function with given fields: ptr
func (_m *UnsafeInterface) Do(ptr *unsafe.Pointer) {
	_m.Called(ptr)
}

type mockConstructorTestingTNewUnsafeInterface interface {
	mock.TestingT
	Cleanup(func())
}

// NewUnsafeInterface creates a new instance of UnsafeInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewUnsafeInterface(t mockConstructorTestingTNewUnsafeInterface) *UnsafeInterface {
	mock := &UnsafeInterface{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("unsafe.go", "UnsafeInterface", false, "", expected)
}

func (s *GeneratorSuite) TestPrologueWithImportSameAsLocalPackage() {
	generator := s.getGenerator(
		"imports_same_as_package.go", "ImportsSameAsPackage", false, "",
	)
	expected := `package mocks

import fixtures "` + generator.iface.QualifiedName + `"
import mock "github.com/stretchr/testify/mock"
import test "github.com/vektra/mockery/v2/pkg/fixtures/test"

`
	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestPrologueWithImportFromNestedInterface() {
	generator := s.getGenerator(
		"imports_from_nested_interface.go", "HasConflictingNestedImports", false, "",
	)
	expected := `package mocks

import fixtureshttp "github.com/vektra/mockery/v2/pkg/fixtures/http"
import http "net/http"
import mock "github.com/stretchr/testify/mock"
import test "github.com/vektra/mockery/v2/pkg/fixtures"

`

	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestGeneratorForStructValueReturn() {
	expected := `// A is an autogenerated mock type for the A type
type A struct {
	mock.Mock
}

// Call provides a mock function with given fields:
func (_m *A) Call() (test.B, error) {
	ret := _m.Called()

	var r0 test.B
	if rf, ok := ret.Get(0).(func() test.B); ok {
		r0 = rf()
	} else {
		r0 = ret.Get(0).(test.B)
	}

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

	return r0, r1
}

type mockConstructorTestingTNewA interface {
	mock.TestingT
	Cleanup(func())
}

// NewA creates a new instance of A. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewA(t mockConstructorTestingTNewA) *A {
	mock := &A{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("struct_value.go", "A", false, "", expected)
}

func (s *GeneratorSuite) TestStructNameOverride() {
	expected := `// Requester2OverrideName is an autogenerated mock type for the Requester2 type
type Requester2OverrideName struct {
	mock.Mock
}

// Get provides a mock function with given fields: path
func (_m *Requester2OverrideName) Get(path string) error {
	ret := _m.Called(path)

	var r0 error
	if rf, ok := ret.Get(0).(func(string) error); ok {
		r0 = rf(path)
	} else {
		r0 = ret.Error(0)
	}

	return r0
}

type mockConstructorTestingTNewRequester2OverrideName interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequester2OverrideName creates a new instance of Requester2OverrideName. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequester2OverrideName(t mockConstructorTestingTNewRequester2OverrideName) *Requester2OverrideName {
	mock := &Requester2OverrideName{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration(testFile2, "Requester2", false, "Requester2OverrideName", expected)
}

func (s *GeneratorSuite) TestKeepTreeInPackageCombined() {
	type testData struct {
		path     string
		name     string
		expected string
	}

	tests := []testData{
		{path: filepath.Join("example_project", "root.go"), name: "Root", expected: `package example_project

import fixturesexample_project "github.com/vektra/mockery/v2/pkg/fixtures/example_project"
import foo "github.com/vektra/mockery/v2/pkg/fixtures/example_project/foo"
import mock "github.com/stretchr/testify/mock"

`},
		{path: filepath.Join("example_project", "foo", "foo.go"), name: "Foo", expected: `package foo

import example_projectfoo "github.com/vektra/mockery/v2/pkg/fixtures/example_project/foo"
import mock "github.com/stretchr/testify/mock"

`},
	}

	for _, test := range tests {
		generator := NewGenerator(
			s.ctx,
			config.Config{InPackage: true, KeepTree: true},
			s.getInterfaceFromFile(test.path, test.name),
			pkg,
		)
		s.checkPrologueGeneration(generator, test.expected)
	}
}

func (s *GeneratorSuite) TestInPackagePackageCollision() {
	expected := `package foo

import barfoo "github.com/vektra/mockery/v2/pkg/fixtures/example_project/bar/foo"
import mock "github.com/stretchr/testify/mock"

`
	generator := NewGenerator(
		s.ctx,
		config.Config{InPackage: true, LogLevel: "debug"},
		s.getInterfaceFromFile("example_project/foo/pkg_name_same_as_import.go", "PackageNameSameAsImport"),
		pkg,
	)
	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestImportCollideWithStdLib() {
	expected := `package context

import context2 "context"
import mock "github.com/stretchr/testify/mock"

`
	generator := NewGenerator(
		s.ctx,
		config.Config{InPackage: true, LogLevel: "debug"},
		s.getInterfaceFromFile("example_project/context/context.go", "CollideWithStdLib"),
		pkg,
	)
	s.checkPrologueGeneration(generator, expected)
}

func (s *GeneratorSuite) TestGenericGenerator() {
	expected := `// RequesterGenerics is an autogenerated mock type for the RequesterGenerics type
type RequesterGenerics[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}] struct {
	mock.Mock
}

// GenericAnonymousStructs provides a mock function with given fields: _a0
func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericAnonymousStructs(_a0 struct{ Type1 TExternalIntf }) struct {
	Type2 test.GenericType[string, test.EmbeddedGet[int]]
} {
	ret := _m.Called(_a0)

	var r0 struct {
		Type2 test.GenericType[string, test.EmbeddedGet[int]]
	}
	if rf, ok := ret.Get(0).(func(struct{ Type1 TExternalIntf }) struct {
		Type2 test.GenericType[string, test.EmbeddedGet[int]]
	}); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(struct {
			Type2 test.GenericType[string, test.EmbeddedGet[int]]
		})
	}

	return r0
}

// GenericArguments provides a mock function with given fields: _a0, _a1
func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericArguments(_a0 TAny, _a1 TComparable) (TSigned, TIntf) {
	ret := _m.Called(_a0, _a1)

	var r0 TSigned
	if rf, ok := ret.Get(0).(func(TAny, TComparable) TSigned); ok {
		r0 = rf(_a0, _a1)
	} else {
		r0 = ret.Get(0).(TSigned)
	}

	var r1 TIntf
	if rf, ok := ret.Get(1).(func(TAny, TComparable) TIntf); ok {
		r1 = rf(_a0, _a1)
	} else {
		r1 = ret.Get(1).(TIntf)
	}

	return r0, r1
}

// GenericStructs provides a mock function with given fields: _a0
func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericStructs(_a0 test.GenericType[TAny, TIntf]) test.GenericType[TSigned, TIntf] {
	ret := _m.Called(_a0)

	var r0 test.GenericType[TSigned, TIntf]
	if rf, ok := ret.Get(0).(func(test.GenericType[TAny, TIntf]) test.GenericType[TSigned, TIntf]); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(test.GenericType[TSigned, TIntf])
	}

	return r0
}

type mockConstructorTestingTNewRequesterGenerics interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterGenerics creates a new instance of RequesterGenerics. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterGenerics[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}](t mockConstructorTestingTNewRequesterGenerics) *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	mock := &RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("generic.go", "RequesterGenerics", false, "", expected)
}

func (s *GeneratorSuite) TestGenericExpecterGenerator() {
	expected := `// RequesterGenerics is an autogenerated mock type for the RequesterGenerics type
type RequesterGenerics[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}] struct {
	mock.Mock
}

type RequesterGenerics_Expecter[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}] struct {
	mock *mock.Mock
}

func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) EXPECT() *RequesterGenerics_Expecter[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	return &RequesterGenerics_Expecter[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{mock: &_m.Mock}
}

// GenericAnonymousStructs provides a mock function with given fields: _a0
func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericAnonymousStructs(_a0 struct{ Type1 TExternalIntf }) struct {
	Type2 test.GenericType[string, test.EmbeddedGet[int]]
} {
	ret := _m.Called(_a0)

	var r0 struct {
		Type2 test.GenericType[string, test.EmbeddedGet[int]]
	}
	if rf, ok := ret.Get(0).(func(struct{ Type1 TExternalIntf }) struct {
		Type2 test.GenericType[string, test.EmbeddedGet[int]]
	}); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(struct {
			Type2 test.GenericType[string, test.EmbeddedGet[int]]
		})
	}

	return r0
}

// RequesterGenerics_GenericAnonymousStructs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenericAnonymousStructs'
type RequesterGenerics_GenericAnonymousStructs_Call[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}] struct {
	*mock.Call
}

// GenericAnonymousStructs is a helper method to define mock.On call
//   - _a0 struct{Type1 TExternalIntf}
func (_e *RequesterGenerics_Expecter[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericAnonymousStructs(_a0 interface{}) *RequesterGenerics_GenericAnonymousStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	return &RequesterGenerics_GenericAnonymousStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{Call: _e.mock.On("GenericAnonymousStructs", _a0)}
}

func (_c *RequesterGenerics_GenericAnonymousStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) Run(run func(_a0 struct{ Type1 TExternalIntf })) *RequesterGenerics_GenericAnonymousStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(struct{ Type1 TExternalIntf }))
	})
	return _c
}

func (_c *RequesterGenerics_GenericAnonymousStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) Return(_a0 struct {
	Type2 test.GenericType[string, test.EmbeddedGet[int]]
}) *RequesterGenerics_GenericAnonymousStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	_c.Call.Return(_a0)
	return _c
}

// GenericArguments provides a mock function with given fields: _a0, _a1
func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericArguments(_a0 TAny, _a1 TComparable) (TSigned, TIntf) {
	ret := _m.Called(_a0, _a1)

	var r0 TSigned
	if rf, ok := ret.Get(0).(func(TAny, TComparable) TSigned); ok {
		r0 = rf(_a0, _a1)
	} else {
		r0 = ret.Get(0).(TSigned)
	}

	var r1 TIntf
	if rf, ok := ret.Get(1).(func(TAny, TComparable) TIntf); ok {
		r1 = rf(_a0, _a1)
	} else {
		r1 = ret.Get(1).(TIntf)
	}

	return r0, r1
}

// RequesterGenerics_GenericArguments_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenericArguments'
type RequesterGenerics_GenericArguments_Call[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}] struct {
	*mock.Call
}

// GenericArguments is a helper method to define mock.On call
//   - _a0 TAny
//   - _a1 TComparable
func (_e *RequesterGenerics_Expecter[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericArguments(_a0 interface{}, _a1 interface{}) *RequesterGenerics_GenericArguments_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	return &RequesterGenerics_GenericArguments_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{Call: _e.mock.On("GenericArguments", _a0, _a1)}
}

func (_c *RequesterGenerics_GenericArguments_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) Run(run func(_a0 TAny, _a1 TComparable)) *RequesterGenerics_GenericArguments_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(TAny), args[1].(TComparable))
	})
	return _c
}

func (_c *RequesterGenerics_GenericArguments_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) Return(_a0 TSigned, _a1 TIntf) *RequesterGenerics_GenericArguments_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	_c.Call.Return(_a0, _a1)
	return _c
}

// GenericStructs provides a mock function with given fields: _a0
func (_m *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericStructs(_a0 test.GenericType[TAny, TIntf]) test.GenericType[TSigned, TIntf] {
	ret := _m.Called(_a0)

	var r0 test.GenericType[TSigned, TIntf]
	if rf, ok := ret.Get(0).(func(test.GenericType[TAny, TIntf]) test.GenericType[TSigned, TIntf]); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(test.GenericType[TSigned, TIntf])
	}

	return r0
}

// RequesterGenerics_GenericStructs_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GenericStructs'
type RequesterGenerics_GenericStructs_Call[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}] struct {
	*mock.Call
}

// GenericStructs is a helper method to define mock.On call
//   - _a0 test.GenericType[TAny,TIntf]
func (_e *RequesterGenerics_Expecter[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericStructs(_a0 interface{}) *RequesterGenerics_GenericStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	return &RequesterGenerics_GenericStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{Call: _e.mock.On("GenericStructs", _a0)}
}

func (_c *RequesterGenerics_GenericStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) Run(run func(_a0 test.GenericType[TAny, TIntf])) *RequesterGenerics_GenericStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	_c.Call.Run(func(args mock.Arguments) {
		run(args[0].(test.GenericType[TAny, TIntf]))
	})
	return _c
}

func (_c *RequesterGenerics_GenericStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) Return(_a0 test.GenericType[TSigned, TIntf]) *RequesterGenerics_GenericStructs_Call[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	_c.Call.Return(_a0)
	return _c
}

type mockConstructorTestingTNewRequesterGenerics interface {
	mock.TestingT
	Cleanup(func())
}

// NewRequesterGenerics creates a new instance of RequesterGenerics. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewRequesterGenerics[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf test.GetInt, TExternalIntf io.Writer, TGenIntf test.GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | test.GenericType[int, test.GetInt]
	comparable
}](t mockConstructorTestingTNewRequesterGenerics) *RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	mock := &RequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{}
	mock.Mock.Test(t)

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

	return mock
}
`
	cfg := config.Config{
		StructName:     "RequesterGenerics",
		WithExpecter:   true,
		UnrollVariadic: true,
	}
	s.checkGenerationWithConfig("generic.go", "RequesterGenerics", cfg, expected)
}

func (s *GeneratorSuite) TestGenericInpkgGenerator() {
	expected := `// MockRequesterGenerics is an autogenerated mock type for the RequesterGenerics type
type MockRequesterGenerics[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf GetInt, TExternalIntf io.Writer, TGenIntf GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | GenericType[int, GetInt]
	comparable
}] struct {
	mock.Mock
}

// GenericAnonymousStructs provides a mock function with given fields: _a0
func (_m *MockRequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericAnonymousStructs(_a0 struct{ Type1 TExternalIntf }) struct {
	Type2 GenericType[string, EmbeddedGet[int]]
} {
	ret := _m.Called(_a0)

	var r0 struct {
		Type2 GenericType[string, EmbeddedGet[int]]
	}
	if rf, ok := ret.Get(0).(func(struct{ Type1 TExternalIntf }) struct {
		Type2 GenericType[string, EmbeddedGet[int]]
	}); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(struct {
			Type2 GenericType[string, EmbeddedGet[int]]
		})
	}

	return r0
}

// GenericArguments provides a mock function with given fields: _a0, _a1
func (_m *MockRequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericArguments(_a0 TAny, _a1 TComparable) (TSigned, TIntf) {
	ret := _m.Called(_a0, _a1)

	var r0 TSigned
	if rf, ok := ret.Get(0).(func(TAny, TComparable) TSigned); ok {
		r0 = rf(_a0, _a1)
	} else {
		r0 = ret.Get(0).(TSigned)
	}

	var r1 TIntf
	if rf, ok := ret.Get(1).(func(TAny, TComparable) TIntf); ok {
		r1 = rf(_a0, _a1)
	} else {
		r1 = ret.Get(1).(TIntf)
	}

	return r0, r1
}

// GenericStructs provides a mock function with given fields: _a0
func (_m *MockRequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]) GenericStructs(_a0 GenericType[TAny, TIntf]) GenericType[TSigned, TIntf] {
	ret := _m.Called(_a0)

	var r0 GenericType[TSigned, TIntf]
	if rf, ok := ret.Get(0).(func(GenericType[TAny, TIntf]) GenericType[TSigned, TIntf]); ok {
		r0 = rf(_a0)
	} else {
		r0 = ret.Get(0).(GenericType[TSigned, TIntf])
	}

	return r0
}

type mockConstructorTestingTNewMockRequesterGenerics interface {
	mock.TestingT
	Cleanup(func())
}

// NewMockRequesterGenerics creates a new instance of MockRequesterGenerics. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockRequesterGenerics[TAny interface{}, TComparable comparable, TSigned constraints.Signed, TIntf GetInt, TExternalIntf io.Writer, TGenIntf GetGeneric[TSigned], TInlineType interface{ ~int | ~uint }, TInlineTypeGeneric interface {
	~int | GenericType[int, GetInt]
	comparable
}](t mockConstructorTestingTNewMockRequesterGenerics) *MockRequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric] {
	mock := &MockRequesterGenerics[TAny, TComparable, TSigned, TIntf, TExternalIntf, TGenIntf, TInlineType, TInlineTypeGeneric]{}
	mock.Mock.Test(t)

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

	return mock
}
`
	s.checkGeneration("generic.go", "RequesterGenerics", true, "", expected)
}

func TestGeneratorSuite(t *testing.T) {
	generatorSuite := new(GeneratorSuite)
	suite.Run(t, generatorSuite)
}

func TestGenerator_getLocalizedPath(t *testing.T) {
	type fields struct {
		Config            config.Config
		buf               bytes.Buffer
		iface             *Interface
		pkg               string
		localizationCache map[string]string
		packagePathToName map[string]string
		nameToPackagePath map[string]string
		packageRoots      []string
	}
	type args struct {
		ctx  context.Context
		path string
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		want   string
	}{
		{
			name:   "test on-disk",
			fields: fields{localizationCache: make(map[string]string)},
			args:   args{ctx: context.Background(), path: "path/to/file.go"},
			want:   "path/to/",
		},
		{
			name:   "test vendored",
			fields: fields{localizationCache: make(map[string]string)},
			args:   args{ctx: context.Background(), path: "vendor/path/to/file.go"},
			want:   "path/to",
		},
		{
			name:   "test URL",
			fields: fields{localizationCache: make(map[string]string)},
			args:   args{ctx: context.Background(), path: "github.com/vektra/mockery"},
			want:   "github.com/vektra/mockery",
		},
		{
			// NOTE: This test is currently testing for behavior that _should_ be
			// fixed. This is a special case where the import path ends in .go,
			// but we should be getting the full importable URL here.
			// https://github.com/vektra/mockery/pull/487
			name:   "test nats.go",
			fields: fields{localizationCache: make(map[string]string)},
			args:   args{ctx: context.Background(), path: "github.com/nats-io/nats.go"},
			want:   "github.com/nats-io/",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			g := &Generator{
				Config:            tt.fields.Config,
				buf:               tt.fields.buf,
				iface:             tt.fields.iface,
				pkg:               tt.fields.pkg,
				localizationCache: tt.fields.localizationCache,
				packagePathToName: tt.fields.packagePathToName,
				nameToPackagePath: tt.fields.nameToPackagePath,
				packageRoots:      tt.fields.packageRoots,
			}
			if got := g.getLocalizedPath(tt.args.ctx, tt.args.path); got != tt.want {
				t.Errorf("Generator.getLocalizedPath() = %v, want %v", got, tt.want)
			}
		})
	}
}
