// Copyright 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package gomock

import (
	
	
	
	
	
)

// A TestReporter is something that can be used to report test failures.  It
// is satisfied by the standard library's *testing.T.
type TestReporter interface {
	Errorf(format string, args ...any)
	Fatalf(format string, args ...any)
}

// TestHelper is a TestReporter that has the Helper method.  It is satisfied
// by the standard library's *testing.T.
type TestHelper interface {
	TestReporter
	Helper()
}

// cleanuper is used to check if TestHelper also has the `Cleanup` method. A
// common pattern is to pass in a `*testing.T` to
// `NewController(t TestReporter)`. In Go 1.14+, `*testing.T` has a cleanup
// method. This can be utilized to call `Finish()` so the caller of this library
// does not have to.
type cleanuper interface {
	Cleanup(func())
}

// A Controller represents the top-level control of a mock ecosystem.  It
// defines the scope and lifetime of mock objects, as well as their
// expectations.  It is safe to call Controller's methods from multiple
// goroutines. Each test should create a new Controller.
//
//	func TestFoo(t *testing.T) {
//	  ctrl := gomock.NewController(t)
//	  // ..
//	}
//
//	func TestBar(t *testing.T) {
//	  t.Run("Sub-Test-1", st) {
//	    ctrl := gomock.NewController(st)
//	    // ..
//	  })
//	  t.Run("Sub-Test-2", st) {
//	    ctrl := gomock.NewController(st)
//	    // ..
//	  })
//	})
type Controller struct {
	// T should only be called within a generated mock. It is not intended to
	// be used in user code and may be changed in future versions. T is the
	// TestReporter passed in when creating the Controller via NewController.
	// If the TestReporter does not implement a TestHelper it will be wrapped
	// with a nopTestHelper.
	T             TestHelper
	mu            sync.Mutex
	expectedCalls *callSet
	finished      bool
}

// NewController returns a new Controller. It is the preferred way to create a Controller.
//
// Passing [*testing.T] registers cleanup function to automatically call [Controller.Finish]
// when the test and all its subtests complete.
func ( TestReporter,  ...ControllerOption) *Controller {
	,  := .(TestHelper)
	if ! {
		 = &nopTestHelper{}
	}
	 := &Controller{
		T:             ,
		expectedCalls: newCallSet(),
	}
	for ,  := range  {
		.apply()
	}
	if ,  := isCleanuper(.T);  {
		.Cleanup(func() {
			.T.Helper()
			.finish(true, nil)
		})
	}

	return 
}

// ControllerOption configures how a Controller should behave.
type ControllerOption interface {
	apply(*Controller)
}

type overridableExpectationsOption struct{}

// WithOverridableExpectations allows for overridable call expectations
// i.e., subsequent call expectations override existing call expectations
func () overridableExpectationsOption {
	return overridableExpectationsOption{}
}

func ( overridableExpectationsOption) ( *Controller) {
	.expectedCalls = newOverridableCallSet()
}

type cancelReporter struct {
	t      TestHelper
	cancel func()
}

func ( *cancelReporter) ( string,  ...any) {
	.t.Errorf(, ...)
}

func ( *cancelReporter) ( string,  ...any) {
	defer .cancel()
	.t.Fatalf(, ...)
}

func ( *cancelReporter) () {
	.t.Helper()
}

// WithContext returns a new Controller and a Context, which is cancelled on any
// fatal failure.
func ( context.Context,  TestReporter) (*Controller, context.Context) {
	,  := .(TestHelper)
	if ! {
		 = &nopTestHelper{t: }
	}

	,  := context.WithCancel()
	return NewController(&cancelReporter{t: , cancel: }), 
}

type nopTestHelper struct {
	t TestReporter
}

func ( *nopTestHelper) ( string,  ...any) {
	.t.Errorf(, ...)
}

func ( *nopTestHelper) ( string,  ...any) {
	.t.Fatalf(, ...)
}

func ( nopTestHelper) () {}

// RecordCall is called by a mock. It should not be called by user code.
func ( *Controller) ( any,  string,  ...any) *Call {
	.T.Helper()

	 := reflect.ValueOf()
	for  := 0;  < .Type().NumMethod(); ++ {
		if .Type().Method().Name ==  {
			return .RecordCallWithMethodType(, , .Method().Type(), ...)
		}
	}
	.T.Fatalf("gomock: failed finding method %s on %T", , )
	panic("unreachable")
}

// RecordCallWithMethodType is called by a mock. It should not be called by user code.
func ( *Controller) ( any,  string,  reflect.Type,  ...any) *Call {
	.T.Helper()

	 := newCall(.T, , , , ...)

	.mu.Lock()
	defer .mu.Unlock()
	.expectedCalls.Add()

	return 
}

// Call is called by a mock. It should not be called by user code.
func ( *Controller) ( any,  string,  ...any) []any {
	.T.Helper()

	// Nest this code so we can use defer to make sure the lock is released.
	 := func() []func([]any) []any {
		.T.Helper()
		.mu.Lock()
		defer .mu.Unlock()

		,  := .expectedCalls.FindMatch(, , )
		if  != nil {
			// callerInfo's skip should be updated if the number of calls between the user's test
			// and this line changes, i.e. this code is wrapped in another anonymous function.
			// 0 is us, 1 is controller.Call(), 2 is the generated mock, and 3 is the user's test.
			 := callerInfo(3)
			 := make([]string, len())
			for ,  := range  {
				[] = getString()
			}
			.T.Fatalf("Unexpected call to %T.%v(%v) at %s because: %s", , , , , )
		}

		// Two things happen here:
		// * the matching call no longer needs to check prerequisite calls,
		// * and the prerequisite calls are no longer expected, so remove them.
		 := .dropPrereqs()
		for ,  := range  {
			.expectedCalls.Remove()
		}

		 := .call()
		if .exhausted() {
			.expectedCalls.Remove()
		}
		return 
	}()

	var  []any
	for ,  := range  {
		if  := ();  != nil {
			 = 
		}
	}

	return 
}

// Finish checks to see if all the methods that were expected to be called were called.
// It is not idempotent and therefore can only be invoked once.
//
// Note: If you pass a *testing.T into [NewController], you no longer
// need to call ctrl.Finish() in your test methods.
func ( *Controller) () {
	// If we're currently panicking, probably because this is a deferred call.
	// This must be recovered in the deferred function.
	 := recover()
	.finish(false, )
}

// Satisfied returns whether all expected calls bound to this Controller have been satisfied.
// Calling Finish is then guaranteed to not fail due to missing calls.
func ( *Controller) () bool {
	.mu.Lock()
	defer .mu.Unlock()
	return .expectedCalls.Satisfied()
}

func ( *Controller) ( bool,  any) {
	.T.Helper()

	.mu.Lock()
	defer .mu.Unlock()

	if .finished {
		if ,  := isCleanuper(.T); ! {
			.T.Fatalf("Controller.Finish was called more than once. It has to be called exactly once.")
		}
		return
	}
	.finished = true

	// Short-circuit, pass through the panic.
	if  != nil {
		panic()
	}

	// Check that all remaining expected calls are satisfied.
	 := .expectedCalls.Failures()
	for ,  := range  {
		.T.Errorf("missing call(s) to %v", )
	}
	if len() != 0 {
		if ! {
			.T.Fatalf("aborting test due to missing call(s)")
			return
		}
		.T.Errorf("aborting test due to missing call(s)")
	}
}

// callerInfo returns the file:line of the call site. skip is the number
// of stack frames to skip when reporting. 0 is callerInfo's call site.
func ( int) string {
	if , , ,  := runtime.Caller( + 1);  {
		return fmt.Sprintf("%s:%d", , )
	}
	return "unknown file"
}

// isCleanuper checks it if t's base TestReporter has a Cleanup method.
func ( TestReporter) (cleanuper, bool) {
	 := unwrapTestReporter()
	,  := .(cleanuper)
	return , 
}

// unwrapTestReporter unwraps TestReporter to the base implementation.
func ( TestReporter) TestReporter {
	 := 
	switch nt := .(type) {
	case *cancelReporter:
		 = .t
		if ,  := .(*nopTestHelper);  {
			 = .t
		}
	case *nopTestHelper:
		 = .t
	default:
		// not wrapped
	}
	return 
}