diff --git a/ymt_v3/example_test.go b/ymt_v3/example_test.go new file mode 100644 index 0000000..4bb00b7 --- /dev/null +++ b/ymt_v3/example_test.go @@ -0,0 +1,324 @@ +package ymt_v3 + +import ( + "encoding/json" + "fmt" + "testing" +) + +// 测试参数(请替换为实际值) +const ( + testAppID = "your_app_id" + testPrivateKey = `-----BEGIN PRIVATE KEY----- +your_private_key_here +-----END PRIVATE KEY-----` + testPublicKey = `-----BEGIN PUBLIC KEY----- +your_public_key_here +-----END PUBLIC KEY-----` + testKey = "your_encryption_key_16" + testActivityNo = "your_activity_no" +) + +func ExampleClient_KeyOrder() { + // 创建客户端 + client, err := NewClient(&ClientConfig{ + AppID: testAppID, + PrivateKey: testPrivateKey, + PublicKey: testPublicKey, + Key: testKey, + EncryptType: EncryptTypeAES, + Env: EnvTest, + }) + if err != nil { + fmt.Printf("创建客户端失败: %v\n", err) + return + } + + // 获取券码 + resp, err := client.KeyOrder(&KeyOrderRequest{ + OutBizNo: "order_001", + ActivityNo: testActivityNo, + Account: "18666666666", + NotifyURL: "https://notify.example.com/openapi", + }) + if err != nil { + fmt.Printf("获取券码失败: %v\n", err) + return + } + + fmt.Printf("交易号: %s\n", resp.TradeNo) + fmt.Printf("卡密: %s\n", resp.Key) + fmt.Printf("状态: %d\n", resp.Status) + + // Output: + // 交易号: 7251449503000383488 + // 卡密: aZKdU9BymzR6qGRzJM + // 状态: 1 +} + +func ExampleClient_KeyQuery() { + client, _ := NewClient(&ClientConfig{ + AppID: testAppID, + PrivateKey: testPrivateKey, + PublicKey: testPublicKey, + Key: testKey, + EncryptType: EncryptTypeAES, + Env: EnvTest, + }) + + // 按外部业务号查询 + resp, err := client.KeyQuery(&KeyQueryRequest{ + OutBizNo: "order_001", + }) + if err != nil { + fmt.Printf("查询失败: %v\n", err) + return + } + + fmt.Printf("交易号: %s\n", resp.TradeNo) + fmt.Printf("状态: %d\n", resp.Status) +} + +func ExampleClient_KeyDiscard() { + client, _ := NewClient(&ClientConfig{ + AppID: testAppID, + PrivateKey: testPrivateKey, + PublicKey: testPublicKey, + Key: testKey, + EncryptType: EncryptTypeAES, + Env: EnvTest, + }) + + // 按交易号作废 + resp, err := client.KeyDiscard(&KeyDiscardRequest{ + TradeNo: "7251449503000383488", + }) + if err != nil { + fmt.Printf("作废失败: %v\n", err) + return + } + + fmt.Printf("交易号: %s\n", resp.TradeNo) + fmt.Printf("状态: %d\n", resp.Status) +} + +func ExampleClient_BatchOrder() { + client, _ := NewClient(&ClientConfig{ + AppID: testAppID, + PrivateKey: testPrivateKey, + PublicKey: testPublicKey, + Key: testKey, + EncryptType: EncryptTypeAES, + Env: EnvTest, + }) + + // 批量发卡 + resp, err := client.BatchOrder(&BatchOrderRequest{ + OutBizNo: "batch_001", + ActivityNo: testActivityNo, + Number: 100, + NotifyURL: "https://notify.example.com/openapi", + }) + if err != nil { + fmt.Printf("批量发卡失败: %v\n", err) + return + } + + fmt.Printf("交易号: %s\n", resp.TradeNo) + fmt.Printf("状态: %s\n", resp.Status) +} + +func ExampleClient_BatchQuery() { + client, _ := NewClient(&ClientConfig{ + AppID: testAppID, + PrivateKey: testPrivateKey, + PublicKey: testPublicKey, + Key: testKey, + EncryptType: EncryptTypeAES, + Env: EnvTest, + }) + + // 查询批量任务 + resp, err := client.BatchQuery(&BatchQueryRequest{ + TradeNo: "7251449503000383499", + }) + if err != nil { + fmt.Printf("查询失败: %v\n", err) + return + } + + fmt.Printf("状态: %s\n", resp.Status) + if resp.DownloadURL != "" { + fmt.Printf("下载地址: %s\n", resp.DownloadURL) + } +} + +func TestMarshalWithoutZero(t *testing.T) { + req := KeyOrderRequest{ + OutBizNo: "order_001", + ActivityNo: "ACT20260622001", + // Account和NotifyURL为空,应该被去掉 + } + + result, err := marshalWithoutZero(req) + if err != nil { + t.Fatalf("marshalWithoutZero失败: %v", err) + } + + expected := `{"activity_no":"ACT20260622001","out_biz_no":"order_001"}` + if result != expected { + t.Errorf("期望 %s, 得到 %s", expected, result) + } +} + +func TestBuildSignStr(t *testing.T) { + appID := "123456" + timestamp := "2026-06-22 15:30:00" + ciphertext := "encrypted_data" + + signStr := BuildSignStr(appID, timestamp, ciphertext) + expected := "1234562026-06-22 15:30:00encrypted_data" + if signStr != expected { + t.Errorf("期望 %s, 得到 %s", expected, signStr) + } +} + +func TestGenerateTimestamp(t *testing.T) { + ts := GenerateTimestamp() + // 验证格式 yyyy-MM-dd HH:mm:ss + if len(ts) != 19 { + t.Errorf("时间戳格式错误: %s", ts) + } +} + +func TestEncryptDecryptAES(t *testing.T) { + key := []byte("1234567890123456") // 16字节 + plaintext := `{"out_biz_no":"order_001","activity_no":"ACT001"}` + + ciphertext, err := AESECBEncrypt([]byte(plaintext), key) + if err != nil { + t.Fatalf("加密失败: %v", err) + } + + decrypted, err := AESECBDecrypt(ciphertext, key) + if err != nil { + t.Fatalf("解密失败: %v", err) + } + + if string(decrypted) != plaintext { + t.Errorf("解密结果不匹配: 期望 %s, 得到 %s", plaintext, string(decrypted)) + } +} + +func TestEncryptDecryptSM4(t *testing.T) { + key := []byte("1234567890123456") // 16字节 + plaintext := `{"out_biz_no":"order_001","activity_no":"ACT001"}` + + ciphertext, err := SM4CBCEncrypt([]byte(plaintext), key) + if err != nil { + t.Fatalf("SM4加密失败: %v", err) + } + + decrypted, err := SM4CBCDecrypt(ciphertext, key) + if err != nil { + t.Fatalf("SM4解密失败: %v", err) + } + + if string(decrypted) != plaintext { + t.Errorf("SM4解密结果不匹配: 期望 %s, 得到 %s", plaintext, string(decrypted)) + } +} + +func TestEncryptBizParams(t *testing.T) { + key := []byte("1234567890123456") + req := KeyOrderRequest{ + OutBizNo: "order_001", + ActivityNo: "ACT20260622001", + } + + ciphertext, err := EncryptBizParams(req, key, EncryptTypeAES) + if err != nil { + t.Fatalf("加密业务参数失败: %v", err) + } + + if ciphertext == "" { + t.Fatal("加密结果为空") + } + + // 验证可以解密 + decrypted, err := DecryptBizParams(ciphertext, key, EncryptTypeAES) + if err != nil { + t.Fatalf("解密失败: %v", err) + } + + var result KeyOrderRequest + if err := json.Unmarshal(decrypted, &result); err != nil { + t.Fatalf("解析失败: %v", err) + } + + if result.OutBizNo != "order_001" { + t.Errorf("OutBizNo不匹配: 期望 order_001, 得到 %s", result.OutBizNo) + } +} + +func TestNewClient(t *testing.T) { + _, err := NewClient(&ClientConfig{ + AppID: testAppID, + PrivateKey: testPrivateKey, + PublicKey: testPublicKey, + Key: testKey, + EncryptType: EncryptTypeAES, + Env: EnvTest, + }) + if err != nil { + t.Fatalf("创建客户端失败: %v", err) + } +} + +func TestNewClientMissingFields(t *testing.T) { + tests := []struct { + name string + config *ClientConfig + wantErr bool + }{ + {"空AppID", &ClientConfig{PrivateKey: "pk", PublicKey: "pub", Key: "key"}, true}, + {"空PrivateKey", &ClientConfig{AppID: "app", PublicKey: "pub", Key: "key"}, true}, + {"空PublicKey", &ClientConfig{AppID: "app", PrivateKey: "pk", Key: "key"}, true}, + {"空Key", &ClientConfig{AppID: "app", PrivateKey: "pk", PublicKey: "pub"}, true}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewClient(tt.config) + if (err != nil) != tt.wantErr { + t.Errorf("NewClient() error = %v, wantErr = %v", err, tt.wantErr) + } + }) + } +} + +func TestAPIError(t *testing.T) { + err := NewAPIError(401, "Signature verification failed", "INVALID_SIGNATURE") + if err.Code != 401 { + t.Errorf("Code不匹配: 期望 401, 得到 %d", err.Code) + } + if err.Message != "Signature verification failed" { + t.Errorf("Message不匹配") + } + if err.Reason != "INVALID_SIGNATURE" { + t.Errorf("Reason不匹配") + } + if err.Error() != "API error: code=401, message=Signature verification failed, reason=INVALID_SIGNATURE" { + t.Errorf("Error()不匹配: %s", err.Error()) + } + if err.IsSuccess() { + t.Error("401应该不是成功") + } +} + +func TestSDKError(t *testing.T) { + err := NewSDKError("测试错误", nil) + if err.Error() != "SDK error: 测试错误" { + t.Errorf("Error()不匹配: %s", err.Error()) + } +} \ No newline at end of file