github.com/tencent/goom@v1.0.1/iface.go (about)

     1  // Package mocker 定义了 mock 的外层用户使用 API 定义,
     2  // 包括函数、方法、接口、未导出函数(或方法的)的 Mocker 的实现。
     3  // 当前文件实现了接口 mock 的能力。
     4  package mocker
     5  
     6  import (
     7  	"fmt"
     8  	"reflect"
     9  	"unsafe"
    10  
    11  	"github.com/tencent/goom/internal/iface"
    12  	"github.com/tencent/goom/internal/logger"
    13  )
    14  
    15  // IContext 接口 mock 的接收体
    16  // 和 internal/proxy.IContext 保持同步
    17  type IContext struct {
    18  	// Data 可以传递任意数据
    19  	Data interface{}
    20  	// 占位属性
    21  	_ unsafe.Pointer
    22  }
    23  
    24  // InterfaceMocker 接口 Mock
    25  // 通过生成和替代接口变量实现 Mock
    26  type InterfaceMocker interface {
    27  	ExportedMocker
    28  	// Method 指定接口方法
    29  	Method(name string) InterfaceMocker
    30  	// As 将接口方法应用为函数类型
    31  	// As 调用之后,请使用 Return 或 When API 的方式来指定 mock 返回。
    32  	// aFunc 函数的第一个参数必须为*mocker.IContext, 作用是指定接口实现的接收体; 后续的参数原样照抄。
    33  	As(aFunc interface{}) InterfaceMocker
    34  	// Inject 将 mock 设置到变量
    35  	Inject(iFace interface{}) InterfaceMocker
    36  }
    37  
    38  // DefaultInterfaceMocker 默认接口 Mocker
    39  type DefaultInterfaceMocker struct {
    40  	*baseMocker
    41  	ctx     *iface.IContext
    42  	iFace   interface{}
    43  	method  string
    44  	funcDef interface{}
    45  }
    46  
    47  // String 接口 Mock 名称
    48  func (m *DefaultInterfaceMocker) String() string {
    49  	t := reflect.TypeOf(m.iFace)
    50  	if t.Kind() == reflect.Ptr {
    51  		t = t.Elem()
    52  	}
    53  	return fmt.Sprintf("%s.%s", t.String(), m.method)
    54  }
    55  
    56  // NewDefaultInterfaceMocker 创建默认接口 Mocker
    57  // pkgName 包路径
    58  // iFace 接口变量定义
    59  func NewDefaultInterfaceMocker(pkgName string, iFace interface{}, ctx *iface.IContext) *DefaultInterfaceMocker {
    60  	return &DefaultInterfaceMocker{
    61  		baseMocker: newBaseMocker(pkgName),
    62  		ctx:        ctx,
    63  		iFace:      iFace,
    64  	}
    65  }
    66  
    67  // Method 指定 mock 的方法名
    68  func (m *DefaultInterfaceMocker) Method(name string) InterfaceMocker {
    69  	if name == "" {
    70  		panic("method is empty")
    71  	}
    72  	m.checkMethod(name)
    73  	m.method = name
    74  	return m
    75  }
    76  
    77  // checkMethod 检查是否能找到函数
    78  func (m *DefaultInterfaceMocker) checkMethod(name string) {
    79  	sTyp := reflect.TypeOf(m.iFace).Elem()
    80  	_, ok := sTyp.MethodByName(name)
    81  	if !ok {
    82  		panic("method " + name + " not found on " + sTyp.String())
    83  	}
    84  }
    85  
    86  // Apply 应用接口方法 mock 为实际的接收体方法
    87  // callback 函数的第一个参数必须为*mocker.IContext, 作用是指定接口实现的接收体; 后续的参数原样照抄。
    88  func (m *DefaultInterfaceMocker) Apply(callback interface{}) {
    89  	if m.method == "" {
    90  		panic("method is empty")
    91  	}
    92  	m.applyByIFaceMethod(m.ctx, m.iFace, m.method, callback, nil)
    93  }
    94  
    95  // As 将接口方法 mock 为实际的接收体方法
    96  // aFunc 函数的第一个参数必须为*mocker.IContext, 作用是指定接口实现的接收体; 后续的参数原样照抄。
    97  func (m *DefaultInterfaceMocker) As(aFunc interface{}) InterfaceMocker {
    98  	if m.method == "" {
    99  		panic("method is empty")
   100  	}
   101  	m.funcDef = aFunc
   102  	return m
   103  }
   104  
   105  // When 执行参数匹配时的返回值
   106  func (m *DefaultInterfaceMocker) When(specArg ...interface{}) *When {
   107  	if m.method == "" {
   108  		panic("method is empty")
   109  	}
   110  	if m.when != nil {
   111  		return m.when.When(specArg...)
   112  	}
   113  
   114  	var (
   115  		when *When
   116  		err  error
   117  	)
   118  	if when, err = CreateWhen(m, m.funcDef, specArg, nil, true); err != nil {
   119  		panic(err)
   120  	}
   121  	m.applyByIFaceMethod(m.ctx, m.iFace, m.method, m.funcDef, m.callback)
   122  	m.when = when
   123  	return when
   124  }
   125  
   126  // Return 指定返回值
   127  func (m *DefaultInterfaceMocker) Return(value ...interface{}) *When {
   128  	if m.funcDef == nil {
   129  		panic("must use As() API before call Return()")
   130  	}
   131  	if m.method == "" {
   132  		panic("method is empty")
   133  	}
   134  	if m.when != nil {
   135  		return m.when.Return(value...)
   136  	}
   137  
   138  	var (
   139  		when *When
   140  		err  error
   141  	)
   142  	if when, err = CreateWhen(m, m.funcDef, nil, value, true); err != nil {
   143  		panic(err)
   144  	}
   145  	m.applyByIFaceMethod(m.ctx, m.iFace, m.method, m.funcDef, m.callback)
   146  	m.when = when
   147  	return when
   148  }
   149  
   150  // Returns 指定返回多个值
   151  func (m *DefaultInterfaceMocker) Returns(values ...interface{}) *When {
   152  	if m.funcDef == nil {
   153  		panic("must use As() API before call Return()")
   154  	}
   155  	if m.method == "" {
   156  		panic("method is empty")
   157  	}
   158  	if m.when != nil {
   159  		return m.when.Returns(values...)
   160  	}
   161  
   162  	var (
   163  		when *When
   164  		err  error
   165  	)
   166  	if when, err = CreateWhen(m, m.funcDef, nil, nil, true); err != nil {
   167  		panic(err)
   168  	}
   169  	when.Returns(values...)
   170  	m.applyByIFaceMethod(m.ctx, m.iFace, m.method, m.funcDef, m.callback)
   171  	m.when = when
   172  	return when
   173  }
   174  
   175  // Origin 回调原函数(暂时不支持)
   176  func (m *DefaultInterfaceMocker) Origin(interface{}) ExportedMocker {
   177  	panic("implement me")
   178  }
   179  
   180  // Inject 回调原函数(暂时不支持)
   181  func (m *DefaultInterfaceMocker) Inject(interface{}) InterfaceMocker {
   182  	panic("implement me")
   183  }
   184  
   185  // applyByIFaceMethod 根据接口方法应用 mock
   186  func (m *DefaultInterfaceMocker) applyByIFaceMethod(ctx *iface.IContext, iFace interface{},
   187  	method string, callback interface{}, implV iface.PFunc) {
   188  	callback, implV = interceptDebugInfo(callback, implV, m)
   189  	m.baseMocker.applyByIFaceMethod(ctx, iFace, method, callback, implV)
   190  	logger.Consolefc(logger.DebugLevel, "mocker [%s] apply.", logger.Caller(6), m.String())
   191  }