package container

import (
	"LAPP_LF_MOM_BACKEND/web/models"
	"errors"
	"github.com/go-xorm/xorm"
	"reflect"
	"testing"
)

func TestNewSessionBroker_Call_WithNull(t *testing.T) {

	out := []reflect.Value{reflect.ValueOf(123), reflect.ValueOf("456"), reflect.ValueOf(nil)}
	parameters := []reflect.Value{reflect.ValueOf(&RequestContext{}), reflect.ValueOf(456)}

	synchronizer1 := NewSynchronizer()
	synchronizer2 := NewSynchronizer()

	callNumberOfTimes := 0
	transactionHandler := &TransactionHandlerMock{}
	transactionHandlerFactory := &TransactionHandlerFactoryMock{handler: transactionHandler}
	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactory)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	var inFromCalling []reflect.Value = nil
	caller := func(in []reflect.Value) []reflect.Value {
		callNumberOfTimes++
		synchronizer1.Awake()
		synchronizer2.Wait()
		inFromCalling = in
		return out
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}

	var result []reflect.Value = nil
	go func() {
		result = broker(parameters)
		synchronizer1.Awake()
	}()
	synchronizer1.Wait()
	if callNumberOfTimes != 1 {
		t.Fatalf("调用中次数错误!")
	}
	if transactionHandler.closeNumberOfTimes != 0 {
		t.Fatalf("调用中关闭次数错误!")
	}
	synchronizer2.Awake()
	synchronizer1.Wait()

	if callNumberOfTimes != 1 {
		t.Fatalf("结束时调用次数错误!")
	}
	if transactionHandler.closeNumberOfTimes != 1 {
		t.Fatalf("结束时关闭次数错误!")
	}

	// Begin 检查参数
	if len(parameters) != len(inFromCalling) {
		t.Fatalf("参数长度错误!")
	}
	requestContext, ok := inFromCalling[0].Interface().(*RequestContext)
	if !ok {
		t.Fatalf("第一个参数类型错误!")
	}
	if transactionHandler.session != requestContext.session {
		t.Fatalf("*RequestContext设置错误!")
	}
	for i := 1; i < len(parameters); i++ {
		if parameters[i].Interface() != inFromCalling[i].Interface() {
			t.Fatalf("参数内容错误!")
		}
	}
	// End 检查参数

	// Begin 检查返回值
	if len(result) != len(out) {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if err, ok := lastReturnValue.(error); ok {
		t.Fatalf("意外错误:%s", err.Error())
	}
	for i := 0; i < len(result); i++ {
		if result[i].Kind() != reflect.Invalid {
			if out[i].Kind() != reflect.Invalid {
				if result[i].Interface() != out[i].Interface() {
					t.Fatalf("返回值内容错误!")
				}
			} else {
				t.Fatalf("返回值内容错误!")
			}
		} else {
			if out[i].Kind() != reflect.Invalid {
				t.Fatalf("返回值内容错误!")
			}
		}
	}
	// End 检查返回值
}

func TestNewSessionBroker_Call_WithNullPointer(t *testing.T) {

	out := []reflect.Value{reflect.ValueOf(123), reflect.ValueOf("456"), reflect.ValueOf(nil)}
	parameters := []reflect.Value{reflect.ValueOf(&RequestContext{}), reflect.ValueOf(456)}

	synchronizer1 := NewSynchronizer()
	synchronizer2 := NewSynchronizer()

	callNumberOfTimes := 0
	transactionHandler := &TransactionHandlerMock{}
	transactionHandlerFactory := &TransactionHandlerFactoryMock{handler: transactionHandler}
	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactory)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	var inFromCalling []reflect.Value = nil
	caller := func(in []reflect.Value) []reflect.Value {
		callNumberOfTimes++
		synchronizer1.Awake()
		synchronizer2.Wait()
		inFromCalling = in
		return out
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}

	var result []reflect.Value = nil
	go func() {
		result = broker(parameters)
		synchronizer1.Awake()
	}()
	synchronizer1.Wait()
	if callNumberOfTimes != 1 {
		t.Fatalf("调用中次数错误!")
	}
	if transactionHandler.closeNumberOfTimes != 0 {
		t.Fatalf("调用中关闭次数错误!")
	}
	synchronizer2.Awake()
	synchronizer1.Wait()

	if callNumberOfTimes != 1 {
		t.Fatalf("结束时调用次数错误!")
	}
	if transactionHandler.closeNumberOfTimes != 1 {
		t.Fatalf("结束时关闭次数错误!")
	}

	// Begin 检查参数
	if len(parameters) != len(inFromCalling) {
		t.Fatalf("参数长度错误!")
	}
	requestContext, ok := inFromCalling[0].Interface().(*RequestContext)
	if !ok {
		t.Fatalf("第一个参数类型错误!")
	}
	if transactionHandler.session != requestContext.session {
		t.Fatalf("*RequestContext设置错误!")
	}
	for i := 1; i < len(parameters); i++ {
		if parameters[i].Interface() != inFromCalling[i].Interface() {
			t.Fatalf("参数内容错误!")
		}
	}
	// End 检查参数

	// Begin 检查返回值
	if len(result) != len(out) {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if err, ok := lastReturnValue.(error); ok {
		t.Fatalf("意外错误:%s", err.Error())
	}
	for i := 0; i < len(result); i++ {
		if result[i].Kind() != reflect.Invalid {
			if out[i].Kind() != reflect.Invalid {
				if result[i].Interface() != out[i].Interface() {
					t.Fatalf("返回值内容错误!")
				}
			} else {
				t.Fatalf("返回值内容错误!")
			}
		} else {
			if out[i].Kind() != reflect.Invalid {
				t.Fatalf("返回值内容错误!")
			}
		}
	}
	// End 检查返回值
}

func TestNewSessionBroker_Call_Panic(t *testing.T) {

	transactionHandler := &TransactionHandlerMock{}
	transactionHandlerFactory := &TransactionHandlerFactoryMock{handler: transactionHandler}
	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactory)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	var panicValue = "模拟崩溃!"
	caller := func(in []reflect.Value) []reflect.Value {
		panic(panicValue)
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	defer func() {
		if p := recover(); p != nil && p != panicValue {
			t.Fatalf("意外崩溃:%v", p)
		}
		if transactionHandler.closeNumberOfTimes != 1 {
			t.Fatalf("崩溃时关闭次数错误!")
		}
	}()
	result := broker([]reflect.Value{reflect.ValueOf(&RequestContext{})})
	if len(result) > 0 {
		lastReturnValue := result[0].Interface()
		if lastReturnValue == nil {
			t.Fatalf("返回值为空!")
		}
		err, ok := lastReturnValue.(error)
		if ok {
			t.Fatalf("意外错误:%s", err.Error())
		}
	}
	t.Fatalf("意外未崩溃!")
}

func TestNewSessionBroker_Call_Less(t *testing.T) {

	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactoryMock)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	caller := func(in []reflect.Value) []reflect.Value {
		return in
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	result := broker([]reflect.Value{})
	if len(result) != 1 {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if lastReturnValue == nil {
		t.Fatalf("返回值为空!")
	}
	err, ok := lastReturnValue.(error)
	if !ok {
		t.Fatalf("返回值类型错误!")
	}
	if err.Error() != "参数长度错误!" {
		t.Fatalf("意外错误:%s", err.Error())
	}
}

func TestNewSessionBroker_Call_ValueTypeError(t *testing.T) {

	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactoryMock)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	caller := func(in []reflect.Value) []reflect.Value {
		return in
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	result := broker([]reflect.Value{reflect.ValueOf(RequestContext{}), reflect.ValueOf("123")})
	if len(result) != 1 {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if lastReturnValue == nil {
		t.Fatalf("返回值为空!")
	}
	err, ok := lastReturnValue.(error)
	if !ok {
		t.Fatalf("返回值类型错误!")
	}
	if err.Error() != "第一个参数类型错误!" {
		t.Fatalf("意外错误:%s", err.Error())
	}
}

func TestNewSessionBroker_Call_PointerTypeError(t *testing.T) {

	transactionHandler := &TransactionHandlerMock{}
	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactoryMock)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	caller := func(in []reflect.Value) []reflect.Value {
		return in
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	result := broker([]reflect.Value{reflect.ValueOf(transactionHandler)})
	if len(result) != 1 {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if lastReturnValue == nil {
		t.Fatalf("返回值为空!")
	}
	err, ok := lastReturnValue.(error)
	if !ok {
		t.Fatalf("返回值类型错误!")
	}
	if err.Error() != "第一个参数类型不正确!" {
		t.Fatalf("意外错误:%s", err.Error())
	}
}

func TestNewSessionBroker_Call_Repeated(t *testing.T) {

	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactoryMock)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	caller := func(in []reflect.Value) []reflect.Value {
		return in
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	result := broker([]reflect.Value{reflect.ValueOf(&RequestContext{session: &xorm.Session{}})})
	if len(result) != 1 {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if lastReturnValue == nil {
		t.Fatalf("返回值为空!")
	}
	err, ok := lastReturnValue.(error)
	if !ok {
		t.Fatalf("返回值类型错误!")
	}
	if err.Error() != "上下文的会话应当为空!" {
		t.Fatalf("意外错误:%s", err.Error())
	}
}

func TestNewSessionBroker_Call_CreateError(t *testing.T) {

	out := []reflect.Value{reflect.ValueOf(123), reflect.ValueOf("456"), reflect.ValueOf(nil)}

	createError := errors.New("createError")
	transactionHandlerFactory := &TransactionHandlerFactoryMock{createError: createError}
	userId := "userId"
	user := &models.Usertab{Userid: userId}
	sessionContext, err := NewSessionContext(user, transactionHandlerFactory)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	caller := func(in []reflect.Value) []reflect.Value {
		return out
	}
	builder := NewNewSessionBrokerBuilder()
	broker, err := builder.Build(sessionContext, caller)
	if err != nil {
		t.Fatalf("意外错误:%s", err.Error())
	}
	result := broker([]reflect.Value{reflect.ValueOf(&RequestContext{})})
	if len(result) != 1 {
		t.Fatalf("返回值长度错误!")
	}
	lastReturnValue := result[0].Interface()
	if lastReturnValue == nil {
		t.Fatalf("返回值为空!")
	}
	err, ok := lastReturnValue.(error)
	if !ok {
		t.Fatalf("返回值类型错误!")
	}
	if err != createError {
		t.Fatalf("意外错误:%s", err.Error())
	}
}
