699 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			699 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package zhicha
 | ||
| 
 | ||
| import (
 | ||
| 	"context"
 | ||
| 	"encoding/json"
 | ||
| 	"errors"
 | ||
| 	"fmt"
 | ||
| 	"strings"
 | ||
| 	"testing"
 | ||
| 	"time"
 | ||
| )
 | ||
| 
 | ||
| func TestGenerateSign(t *testing.T) {
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			AppSecret: "test_secret_123",
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	timestamp := int64(1640995200) // 2022-01-01 00:00:00
 | ||
| 	sign := service.generateSign(timestamp)
 | ||
| 
 | ||
| 	if sign == "" {
 | ||
| 		t.Error("签名生成失败,签名为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证签名长度(MD5是32位十六进制)
 | ||
| 	if len(sign) != 32 {
 | ||
| 		t.Errorf("签名长度错误,期望32位,实际%d位", len(sign))
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证相同参数生成相同签名
 | ||
| 	sign2 := service.generateSign(timestamp)
 | ||
| 	if sign != sign2 {
 | ||
| 		t.Error("相同参数生成的签名不一致")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestEncryptDecrypt(t *testing.T) {
 | ||
| 	// 测试密钥(32位十六进制)
 | ||
| 	key := "1234567890abcdef1234567890abcdef"
 | ||
| 
 | ||
| 	// 测试数据
 | ||
| 	testData := "这是一个测试数据,包含中文和English"
 | ||
| 
 | ||
| 	// 加密
 | ||
| 	encrypted, err := Encrypt(testData, key)
 | ||
| 	if err != nil {
 | ||
| 		t.Fatalf("加密失败: %v", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	if encrypted == "" {
 | ||
| 		t.Error("加密结果为空")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 解密
 | ||
| 	decrypted, err := Decrypt(encrypted, key)
 | ||
| 	if err != nil {
 | ||
| 		t.Fatalf("解密失败: %v", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	if decrypted != testData {
 | ||
| 		t.Errorf("解密结果不匹配,期望: %s, 实际: %s", testData, decrypted)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestEncryptWithInvalidKey(t *testing.T) {
 | ||
| 	// 测试无效密钥
 | ||
| 	invalidKeys := []string{
 | ||
| 		"",                   // 空密钥
 | ||
| 		"123",                // 太短
 | ||
| 		"invalid_key_string", // 非十六进制
 | ||
| 		"1234567890abcdef",   // 16位,不足32位
 | ||
| 	}
 | ||
| 
 | ||
| 	testData := "test data"
 | ||
| 
 | ||
| 	for _, key := range invalidKeys {
 | ||
| 		_, err := Encrypt(testData, key)
 | ||
| 		if err == nil {
 | ||
| 			t.Errorf("使用无效密钥 %s 应该返回错误", key)
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestDecryptWithInvalidData(t *testing.T) {
 | ||
| 	key := "1234567890abcdef1234567890abcdef"
 | ||
| 
 | ||
| 	// 测试无效的加密数据
 | ||
| 	invalidData := []string{
 | ||
| 		"",               // 空数据
 | ||
| 		"invalid_base64", // 无效的Base64
 | ||
| 		"dGVzdA==",       // 有效的Base64但不是AES加密数据
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, data := range invalidData {
 | ||
| 		_, err := Decrypt(data, key)
 | ||
| 		if err == nil {
 | ||
| 			t.Errorf("使用无效数据 %s 应该返回错误", data)
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestPKCS7Padding(t *testing.T) {
 | ||
| 	testCases := []struct {
 | ||
| 		input     string
 | ||
| 		blockSize int
 | ||
| 		expected  int
 | ||
| 	}{
 | ||
| 		{"", 16, 16},
 | ||
| 		{"a", 16, 16},
 | ||
| 		{"ab", 16, 16},
 | ||
| 		{"abc", 16, 16},
 | ||
| 		{"abcd", 16, 16},
 | ||
| 		{"abcde", 16, 16},
 | ||
| 		{"abcdef", 16, 16},
 | ||
| 		{"abcdefg", 16, 16},
 | ||
| 		{"abcdefgh", 16, 16},
 | ||
| 		{"abcdefghi", 16, 16},
 | ||
| 		{"abcdefghij", 16, 16},
 | ||
| 		{"abcdefghijk", 16, 16},
 | ||
| 		{"abcdefghijkl", 16, 16},
 | ||
| 		{"abcdefghijklm", 16, 16},
 | ||
| 		{"abcdefghijklmn", 16, 16},
 | ||
| 		{"abcdefghijklmno", 16, 16},
 | ||
| 		{"abcdefghijklmnop", 16, 16},
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, tc := range testCases {
 | ||
| 		padded := pkcs7Padding([]byte(tc.input), tc.blockSize)
 | ||
| 		if len(padded)%tc.blockSize != 0 {
 | ||
| 			t.Errorf("输入: %s, 期望块大小倍数,实际: %d", tc.input, len(padded))
 | ||
| 		}
 | ||
| 
 | ||
| 		// 测试移除填充
 | ||
| 		unpadded, err := pkcs7Unpadding(padded)
 | ||
| 		if err != nil {
 | ||
| 			t.Errorf("移除填充失败: %v", err)
 | ||
| 		}
 | ||
| 
 | ||
| 		if string(unpadded) != tc.input {
 | ||
| 			t.Errorf("输入: %s, 期望: %s, 实际: %s", tc.input, tc.input, string(unpadded))
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestGenerateRequestID(t *testing.T) {
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			AppID: "test_app_id",
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	id1 := service.generateRequestID()
 | ||
| 
 | ||
| 	// 等待一小段时间确保时间戳不同
 | ||
| 	time.Sleep(time.Millisecond)
 | ||
| 
 | ||
| 	id2 := service.generateRequestID()
 | ||
| 
 | ||
| 	if id1 == "" || id2 == "" {
 | ||
| 		t.Error("请求ID生成失败")
 | ||
| 	}
 | ||
| 
 | ||
| 	if id1 == id2 {
 | ||
| 		t.Error("不同时间生成的请求ID应该不同")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证ID格式
 | ||
| 	if len(id1) < 20 { // zhicha_ + 8位十六进制 + 其他
 | ||
| 		t.Errorf("请求ID长度不足,实际: %s", id1)
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestCallAPISuccess(t *testing.T) {
 | ||
| 	// 创建测试服务
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:        "http://proxy.tianyuanapi.com/dataMiddle/api/handle",
 | ||
| 			AppID:      "4b78fff61ab8426f",
 | ||
| 			AppSecret:  "1128f01b94124ae899c2e9f2b1f37681",
 | ||
| 			EncryptKey: "af4ca0098e6a202a5c08c413ebd9fd62",
 | ||
| 		},
 | ||
| 		logger: nil, // 测试时不使用日志
 | ||
| 	}
 | ||
| 
 | ||
| 	// 测试参数
 | ||
| 	idCardEncrypted, err := service.Encrypt("45212220000827423X")
 | ||
| 	if err != nil {
 | ||
| 		t.Fatalf("加密身份证号失败: %v", err)
 | ||
| 	}
 | ||
| 	nameEncrypted, err := service.Encrypt("张荣宏")
 | ||
| 	if err != nil {
 | ||
| 		t.Fatalf("加密姓名失败: %v", err)
 | ||
| 	}
 | ||
| 	params := map[string]interface{}{
 | ||
| 		"idCard":     idCardEncrypted,
 | ||
| 		"name":       nameEncrypted,
 | ||
| 		"authorized": "1",
 | ||
| 	}
 | ||
| 
 | ||
| 	// 创建带超时的context
 | ||
| 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 | ||
| 	defer cancel()
 | ||
| 
 | ||
| 	// 调用API
 | ||
| 	data, err := service.CallAPI(ctx, "ZCI001", params)
 | ||
| 
 | ||
| 	// 注意:这是真实API调用,可能会因为网络、认证等原因失败
 | ||
| 	// 我们主要测试方法调用是否正常,不强制要求API返回成功
 | ||
| 	if err != nil {
 | ||
| 		// 如果是网络错误或认证错误,这是正常的
 | ||
| 		t.Logf("API调用返回错误: %v", err)
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 如果成功,验证响应
 | ||
| 	if data == nil {
 | ||
| 		t.Error("响应数据为空")
 | ||
| 		return
 | ||
| 	}
 | ||
| 
 | ||
| 	// 将data转换为字符串进行显示
 | ||
| 	var dataStr string
 | ||
| 	if str, ok := data.(string); ok {
 | ||
| 		dataStr = str
 | ||
| 	} else {
 | ||
| 		// 如果不是字符串,尝试JSON序列化
 | ||
| 		if dataBytes, err := json.Marshal(data); err == nil {
 | ||
| 			dataStr = string(dataBytes)
 | ||
| 		} else {
 | ||
| 			dataStr = fmt.Sprintf("%v", data)
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	t.Logf("API调用成功,响应内容: %s", dataStr)
 | ||
| }
 | ||
| 
 | ||
| func TestCallAPIWithInvalidURL(t *testing.T) {
 | ||
| 	// 创建使用无效URL的服务
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:        "https://invalid-url-that-does-not-exist.com/api",
 | ||
| 			AppID:      "test_app_id",
 | ||
| 			AppSecret:  "test_app_secret",
 | ||
| 			EncryptKey: "test_encrypt_key",
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 
 | ||
| 	params := map[string]interface{}{
 | ||
| 		"test": "data",
 | ||
| 	}
 | ||
| 
 | ||
| 	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
 | ||
| 	defer cancel()
 | ||
| 
 | ||
| 	// 应该返回错误
 | ||
| 	_, err := service.CallAPI(ctx, "test_pro_id", params)
 | ||
| 	if err == nil {
 | ||
| 		t.Error("使用无效URL应该返回错误")
 | ||
| 	}
 | ||
| 
 | ||
| 	t.Logf("预期的错误: %v", err)
 | ||
| }
 | ||
| 
 | ||
| func TestCallAPIWithContextCancellation(t *testing.T) {
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:        "https://www.zhichajinkong.com/dataMiddle/api/handle",
 | ||
| 			AppID:      "4b78fff61ab8426f",
 | ||
| 			AppSecret:  "1128f01b94124ae899c2e9f2b1f37681",
 | ||
| 			EncryptKey: "af4ca0098e6a202a5c08c413ebd9fd62",
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 
 | ||
| 	params := map[string]interface{}{
 | ||
| 		"test": "data",
 | ||
| 	}
 | ||
| 
 | ||
| 	// 创建可取消的context
 | ||
| 	ctx, cancel := context.WithCancel(context.Background())
 | ||
| 
 | ||
| 	// 立即取消
 | ||
| 	cancel()
 | ||
| 
 | ||
| 	// 应该返回context取消错误
 | ||
| 	_, err := service.CallAPI(ctx, "test_pro_id", params)
 | ||
| 	if err == nil {
 | ||
| 		t.Error("context取消后应该返回错误")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 检查是否是context取消错误
 | ||
| 	if err != context.Canceled && !strings.Contains(err.Error(), "context") {
 | ||
| 		t.Errorf("期望context相关错误,实际: %v", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	t.Logf("Context取消错误: %v", err)
 | ||
| }
 | ||
| 
 | ||
| func TestCallAPIWithTimeout(t *testing.T) {
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:        "https://www.zhichajinkong.com/dataMiddle/api/handle",
 | ||
| 			AppID:      "4b78fff61ab8426f",
 | ||
| 			AppSecret:  "1128f01b94124ae899c2e9f2b1f37681",
 | ||
| 			EncryptKey: "af4ca0098e6a202a5c08c413ebd9fd62",
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 
 | ||
| 	params := map[string]interface{}{
 | ||
| 		"test": "data",
 | ||
| 	}
 | ||
| 
 | ||
| 	// 创建很短的超时
 | ||
| 	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Millisecond)
 | ||
| 	defer cancel()
 | ||
| 
 | ||
| 	// 应该因为超时而失败
 | ||
| 	_, err := service.CallAPI(ctx, "test_pro_id", params)
 | ||
| 	if err == nil {
 | ||
| 		t.Error("超时后应该返回错误")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 检查是否是超时错误
 | ||
| 	if err != context.DeadlineExceeded && !strings.Contains(err.Error(), "timeout") && !strings.Contains(err.Error(), "deadline") {
 | ||
| 		t.Errorf("期望超时相关错误,实际: %v", err)
 | ||
| 	}
 | ||
| 
 | ||
| 	t.Logf("超时错误: %v", err)
 | ||
| }
 | ||
| 
 | ||
| func TestCallAPIRequestHeaders(t *testing.T) {
 | ||
| 	// 这个测试验证请求头是否正确设置
 | ||
| 	// 由于我们不能直接访问HTTP请求,我们通过日志或其他方式来验证
 | ||
| 
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:        "https://www.zhichajinkong.com/dataMiddle/api/handle",
 | ||
| 			AppID:      "test_app_id",
 | ||
| 			AppSecret:  "test_app_secret",
 | ||
| 			EncryptKey: "test_encrypt_key",
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 
 | ||
| 	params := map[string]interface{}{
 | ||
| 		"test": "headers",
 | ||
| 	}
 | ||
| 
 | ||
| 	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 | ||
| 	defer cancel()
 | ||
| 
 | ||
| 	// 调用API(可能会失败,但我们主要测试请求头设置)
 | ||
| 	_, err := service.CallAPI(ctx, "test_pro_id", params)
 | ||
| 
 | ||
| 	// 验证签名生成是否正确
 | ||
| 	timestamp := time.Now().Unix()
 | ||
| 	sign := service.generateSign(timestamp)
 | ||
| 
 | ||
| 	if sign == "" {
 | ||
| 		t.Error("签名生成失败")
 | ||
| 	}
 | ||
| 
 | ||
| 	if len(sign) != 32 {
 | ||
| 		t.Errorf("签名长度错误,期望32位,实际%d位", len(sign))
 | ||
| 	}
 | ||
| 
 | ||
| 	t.Logf("签名生成成功: %s", sign)
 | ||
| 	t.Logf("API调用结果: %v", err)
 | ||
| }
 | ||
| 
 | ||
| func TestZhichaErrorHandling(t *testing.T) {
 | ||
| 	// 测试核心错误类型
 | ||
| 	testCases := []struct {
 | ||
| 		name        string
 | ||
| 		code        string
 | ||
| 		message     string
 | ||
| 		expectedErr *ZhichaError
 | ||
| 	}{
 | ||
| 		{
 | ||
| 			name:        "成功状态",
 | ||
| 			code:        "200",
 | ||
| 			message:     "请求成功",
 | ||
| 			expectedErr: ErrSuccess,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "查询无记录",
 | ||
| 			code:        "201",
 | ||
| 			message:     "查询无记录",
 | ||
| 			expectedErr: ErrNoRecord,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "手机号错误",
 | ||
| 			code:        "306",
 | ||
| 			message:     "手机号错误",
 | ||
| 			expectedErr: ErrPhoneError,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "姓名错误",
 | ||
| 			code:        "305",
 | ||
| 			message:     "姓名错误",
 | ||
| 			expectedErr: ErrNameError,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "身份证号错误",
 | ||
| 			code:        "307",
 | ||
| 			message:     "身份证号错误",
 | ||
| 			expectedErr: ErrIDCardError,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "余额不足",
 | ||
| 			code:        "310",
 | ||
| 			message:     "余额不足",
 | ||
| 			expectedErr: ErrInsufficientBalance,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "用户不存在",
 | ||
| 			code:        "312",
 | ||
| 			message:     "用户不存在",
 | ||
| 			expectedErr: ErrUserNotExist,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "系统异常",
 | ||
| 			code:        "500",
 | ||
| 			message:     "系统异常,请联系管理员",
 | ||
| 			expectedErr: ErrSystemError,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, tc := range testCases {
 | ||
| 		t.Run(tc.name, func(t *testing.T) {
 | ||
| 			// 测试从状态码创建错误
 | ||
| 			err := NewZhichaErrorFromCode(tc.code)
 | ||
| 
 | ||
| 			if err.Code != tc.expectedErr.Code {
 | ||
| 				t.Errorf("期望错误码 %s,实际 %s", tc.expectedErr.Code, err.Code)
 | ||
| 			}
 | ||
| 
 | ||
| 			if err.Message != tc.expectedErr.Message {
 | ||
| 				t.Errorf("期望错误消息 %s,实际 %s", tc.expectedErr.Message, err.Message)
 | ||
| 			}
 | ||
| 		})
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestZhichaErrorHelpers(t *testing.T) {
 | ||
| 	// 测试错误类型判断函数
 | ||
| 	err := NewZhichaError("302", "业务参数缺失")
 | ||
| 
 | ||
| 	// 测试IsZhichaError
 | ||
| 	if !IsZhichaError(err) {
 | ||
| 		t.Error("IsZhichaError应该返回true")
 | ||
| 	}
 | ||
| 
 | ||
| 	// 测试GetZhichaError
 | ||
| 	zhichaErr := GetZhichaError(err)
 | ||
| 	if zhichaErr == nil {
 | ||
| 		t.Error("GetZhichaError应该返回非nil值")
 | ||
| 	}
 | ||
| 
 | ||
| 	if zhichaErr.Code != "302" {
 | ||
| 		t.Errorf("期望错误码302,实际%s", zhichaErr.Code)
 | ||
| 	}
 | ||
| 
 | ||
| 	// 测试普通错误
 | ||
| 	normalErr := fmt.Errorf("普通错误")
 | ||
| 	if IsZhichaError(normalErr) {
 | ||
| 		t.Error("普通错误不应该被识别为智查金控错误")
 | ||
| 	}
 | ||
| 
 | ||
| 	if GetZhichaError(normalErr) != nil {
 | ||
| 		t.Error("普通错误的GetZhichaError应该返回nil")
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestZhichaErrorString(t *testing.T) {
 | ||
| 	// 测试错误字符串格式
 | ||
| 	err := NewZhichaError("304", "请求头参数缺失")
 | ||
| 	expectedStr := "智查金控错误 [304]: 请求头参数缺失"
 | ||
| 
 | ||
| 	if err.Error() != expectedStr {
 | ||
| 		t.Errorf("期望错误字符串 %s,实际 %s", expectedStr, err.Error())
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestErrorsIsFunctionality(t *testing.T) {
 | ||
| 	// 测试 errors.Is() 功能是否正常工作
 | ||
| 
 | ||
| 	// 创建各种错误
 | ||
| 	testCases := []struct {
 | ||
| 		name        string
 | ||
| 		err         error
 | ||
| 		expected    error
 | ||
| 		shouldMatch bool
 | ||
| 	}{
 | ||
| 		{
 | ||
| 			name:        "手机号错误匹配",
 | ||
| 			err:         ErrPhoneError,
 | ||
| 			expected:    ErrPhoneError,
 | ||
| 			shouldMatch: true,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "姓名错误匹配",
 | ||
| 			err:         ErrNameError,
 | ||
| 			expected:    ErrNameError,
 | ||
| 			shouldMatch: true,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "身份证号错误匹配",
 | ||
| 			err:         ErrIDCardError,
 | ||
| 			expected:    ErrIDCardError,
 | ||
| 			shouldMatch: true,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "余额不足错误匹配",
 | ||
| 			err:         ErrInsufficientBalance,
 | ||
| 			expected:    ErrInsufficientBalance,
 | ||
| 			shouldMatch: true,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "用户不存在错误匹配",
 | ||
| 			err:         ErrUserNotExist,
 | ||
| 			expected:    ErrUserNotExist,
 | ||
| 			shouldMatch: true,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "系统错误匹配",
 | ||
| 			err:         ErrSystemError,
 | ||
| 			expected:    ErrSystemError,
 | ||
| 			shouldMatch: true,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "不同错误不匹配",
 | ||
| 			err:         ErrPhoneError,
 | ||
| 			expected:    ErrNameError,
 | ||
| 			shouldMatch: false,
 | ||
| 		},
 | ||
| 		{
 | ||
| 			name:        "手机号错误与身份证号错误不匹配",
 | ||
| 			err:         ErrPhoneError,
 | ||
| 			expected:    ErrIDCardError,
 | ||
| 			shouldMatch: false,
 | ||
| 		},
 | ||
| 	}
 | ||
| 
 | ||
| 	for _, tc := range testCases {
 | ||
| 		t.Run(tc.name, func(t *testing.T) {
 | ||
| 			// 使用 errors.Is() 进行判断
 | ||
| 			if errors.Is(tc.err, tc.expected) != tc.shouldMatch {
 | ||
| 				if tc.shouldMatch {
 | ||
| 					t.Errorf("期望 errors.Is(%v, %v) 返回 true", tc.err, tc.expected)
 | ||
| 				} else {
 | ||
| 					t.Errorf("期望 errors.Is(%v, %v) 返回 false", tc.err, tc.expected)
 | ||
| 				}
 | ||
| 			}
 | ||
| 		})
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| func TestErrorsIsInSwitch(t *testing.T) {
 | ||
| 	// 测试在 switch 语句中使用 errors.Is()
 | ||
| 
 | ||
| 	// 模拟API调用返回手机号错误
 | ||
| 	err := ErrPhoneError
 | ||
| 
 | ||
| 	// 使用 switch 语句进行错误判断
 | ||
| 	var result string
 | ||
| 	switch {
 | ||
| 	case errors.Is(err, ErrSuccess):
 | ||
| 		result = "请求成功"
 | ||
| 	case errors.Is(err, ErrNoRecord):
 | ||
| 		result = "查询无记录"
 | ||
| 	case errors.Is(err, ErrPhoneError):
 | ||
| 		result = "手机号格式错误"
 | ||
| 	case errors.Is(err, ErrNameError):
 | ||
| 		result = "姓名格式错误"
 | ||
| 	case errors.Is(err, ErrIDCardError):
 | ||
| 		result = "身份证号格式错误"
 | ||
| 	case errors.Is(err, ErrHeaderParamMissing):
 | ||
| 		result = "请求头参数缺失"
 | ||
| 	case errors.Is(err, ErrInsufficientBalance):
 | ||
| 		result = "余额不足"
 | ||
| 	case errors.Is(err, ErrUserNotExist):
 | ||
| 		result = "用户不存在"
 | ||
| 	case errors.Is(err, ErrUserUnauthorized):
 | ||
| 		result = "用户未授权"
 | ||
| 	case errors.Is(err, ErrSystemError):
 | ||
| 		result = "系统异常"
 | ||
| 	default:
 | ||
| 		result = "未知错误"
 | ||
| 	}
 | ||
| 
 | ||
| 	// 验证结果
 | ||
| 	expected := "手机号格式错误"
 | ||
| 	if result != expected {
 | ||
| 		t.Errorf("期望结果 %s,实际 %s", expected, result)
 | ||
| 	}
 | ||
| 
 | ||
| 	t.Logf("Switch语句错误判断结果: %s", result)
 | ||
| }
 | ||
| 
 | ||
| func TestServiceEncryptDecrypt(t *testing.T) {
 | ||
| 	// 创建测试服务
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:        "https://test.com",
 | ||
| 			AppID:      "test_app_id",
 | ||
| 			AppSecret:  "test_app_secret",
 | ||
| 			EncryptKey: "af4ca0098e6a202a5c08c413ebd9fd62",
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 
 | ||
| 	// 测试数据
 | ||
| 	testData := "Hello, 智查金控!"
 | ||
| 	
 | ||
| 	// 测试加密
 | ||
| 	encrypted, err := service.Encrypt(testData)
 | ||
| 	if err != nil {
 | ||
| 		t.Fatalf("加密失败: %v", err)
 | ||
| 	}
 | ||
| 	
 | ||
| 	if encrypted == "" {
 | ||
| 		t.Error("加密结果为空")
 | ||
| 	}
 | ||
| 	
 | ||
| 	if encrypted == testData {
 | ||
| 		t.Error("加密结果与原文相同")
 | ||
| 	}
 | ||
| 	
 | ||
| 	t.Logf("原文: %s", testData)
 | ||
| 	t.Logf("加密后: %s", encrypted)
 | ||
| 	
 | ||
| 	// 测试解密
 | ||
| 	decrypted, err := service.Decrypt(encrypted)
 | ||
| 	if err != nil {
 | ||
| 		t.Fatalf("解密失败: %v", err)
 | ||
| 	}
 | ||
| 	
 | ||
| 	if decrypted != testData {
 | ||
| 		t.Errorf("解密结果不匹配,期望: %s,实际: %s", testData, decrypted)
 | ||
| 	}
 | ||
| 	
 | ||
| 	t.Logf("解密后: %s", decrypted)
 | ||
| }
 | ||
| 
 | ||
| func TestEncryptWithoutKey(t *testing.T) {
 | ||
| 	// 创建没有加密密钥的服务
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:       "https://test.com",
 | ||
| 			AppID:     "test_app_id",
 | ||
| 			AppSecret: "test_app_secret",
 | ||
| 			// 没有设置 EncryptKey
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 	
 | ||
| 	// 应该返回错误
 | ||
| 	_, err := service.Encrypt("test data")
 | ||
| 	if err == nil {
 | ||
| 		t.Error("没有加密密钥时应该返回错误")
 | ||
| 	}
 | ||
| 	
 | ||
| 	if !strings.Contains(err.Error(), "加密密钥未配置") {
 | ||
| 		t.Errorf("期望错误包含'加密密钥未配置',实际: %v", err)
 | ||
| 	}
 | ||
| 	
 | ||
| 	t.Logf("预期的错误: %v", err)
 | ||
| }
 | ||
| 
 | ||
| func TestDecryptWithoutKey(t *testing.T) {
 | ||
| 	// 创建没有加密密钥的服务
 | ||
| 	service := &ZhichaService{
 | ||
| 		config: ZhichaConfig{
 | ||
| 			URL:       "https://test.com",
 | ||
| 			AppID:     "test_app_id",
 | ||
| 			AppSecret: "test_app_secret",
 | ||
| 			// 没有设置 EncryptKey
 | ||
| 		},
 | ||
| 		logger: nil,
 | ||
| 	}
 | ||
| 	
 | ||
| 	// 应该返回错误
 | ||
| 	_, err := service.Decrypt("test encrypted data")
 | ||
| 	if err == nil {
 | ||
| 		t.Error("没有加密密钥时应该返回错误")
 | ||
| 	}
 | ||
| 	
 | ||
| 	if !strings.Contains(err.Error(), "加密密钥未配置") {
 | ||
| 		t.Errorf("期望错误包含'加密密钥未配置',实际: %v", err)
 | ||
| 	}
 | ||
| 	
 | ||
| 	t.Logf("预期的错误: %v", err)
 | ||
| }
 |