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) | |||
|  | } |