a9b6234208
Motivation: 让通知模板能够将 action、event 等原始枚举值映射为可读中文文案,并支持按事件名后缀匹配;同时简化 SafeW 消息发送格式,避免 Markdown 转义引入的显示问题。 Changes: * 新增 `case` 模板函数,按值匹配 key/文案并支持末尾奇数参数作为默认值 * `case` 匹配兼容事件名后缀(如 trade.close 匹配 .close) * `line` 前缀自动去除末尾冒号,避免重复冒号 * 模板渲染前自动注入 event 字段,便于模板按事件名取值 * SafeW 消息改为纯文本发送,移除 MarkdownV2 转义
111 lines
2.9 KiB
Go
111 lines
2.9 KiB
Go
package engine
|
||
|
||
import (
|
||
"strings"
|
||
"testing"
|
||
)
|
||
|
||
func TestRenderer(t *testing.T) {
|
||
r := NewRenderer()
|
||
tmpl := "🚀 {{.symbol}} 开仓通知\n价格: {{.price}}"
|
||
data := map[string]interface{}{"symbol": "BTC", "price": 65000}
|
||
result, err := r.Render(tmpl, data)
|
||
if err != nil {
|
||
t.Fatalf("unexpected error: %v", err)
|
||
}
|
||
if !strings.Contains(result, "BTC") || !strings.Contains(result, "65000") {
|
||
t.Errorf("unexpected output: %s", result)
|
||
}
|
||
}
|
||
|
||
func TestRendererMissingKeyEmpty(t *testing.T) {
|
||
r := NewRenderer()
|
||
_, err := r.Render("x{{.nonexistent}}y", map[string]interface{}{})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
}
|
||
|
||
func TestRendererLineOmitsEmpty(t *testing.T) {
|
||
r := NewRenderer()
|
||
tmpl := `{{line "币种" .symbol}}{{line "平均价" .totalAvgPx}}{{line "价格" .price}}{{line "止损价" .stopLossPrice}}`
|
||
out, err := r.Render(tmpl, map[string]interface{}{
|
||
"symbol": "ICP",
|
||
"price": 2.273,
|
||
"totalAvgPx": "",
|
||
"stopLossPrice": 0,
|
||
})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if !strings.Contains(out, "币种:ICP") || !strings.Contains(out, "价格:2.273") {
|
||
t.Fatalf("out=%q", out)
|
||
}
|
||
if strings.Contains(out, "平均价") || strings.Contains(out, "止损价") {
|
||
t.Fatalf("empty lines should be omitted, out=%q", out)
|
||
}
|
||
}
|
||
|
||
func TestRendererLineLabelAlreadyHasColon(t *testing.T) {
|
||
r := NewRenderer()
|
||
out, err := r.Render(`{{line "平均价:" .totalAvgPx}}`, map[string]interface{}{"totalAvgPx": 1029})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if strings.Count(out, ":") != 1 || !strings.Contains(out, "平均价:1029") {
|
||
t.Fatalf("out=%q", out)
|
||
}
|
||
}
|
||
func TestRendererLineMissingKey(t *testing.T) {
|
||
r := NewRenderer()
|
||
out, err := r.Render(`{{line "平均价" .totalAvgPx}}{{line "币种" .symbol}}`, map[string]interface{}{"symbol": "ICP"})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if strings.Contains(out, "平均价") || !strings.Contains(out, "币种:ICP") {
|
||
t.Fatalf("out=%q", out)
|
||
}
|
||
}
|
||
|
||
func TestRendererCaseSwitch(t *testing.T) {
|
||
r := NewRenderer()
|
||
tmpl := `{{case .action "OPEN" "开仓" "CLOSE" "平仓" "GAIN" "止盈"}}`
|
||
out, err := r.Render(tmpl, map[string]interface{}{"action": "CLOSE"})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if out != "平仓" {
|
||
t.Fatalf("action CLOSE: %q", out)
|
||
}
|
||
out, err = r.Render(tmpl, map[string]interface{}{"action": "open"})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if out != "开仓" {
|
||
t.Fatalf("action open: %q", out)
|
||
}
|
||
}
|
||
|
||
func TestRendererCaseEventSuffix(t *testing.T) {
|
||
r := NewRenderer()
|
||
tmpl := `{{case .event ".open" "开仓" ".close" "平仓"}}`
|
||
out, err := r.Render(tmpl, map[string]interface{}{"event": "trade.close"})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if out != "平仓" {
|
||
t.Fatalf("event trade.close: %q", out)
|
||
}
|
||
}
|
||
|
||
func TestRendererCaseDefault(t *testing.T) {
|
||
r := NewRenderer()
|
||
out, err := r.Render(`{{case .action "OPEN" "开仓" "未知"}}`, map[string]interface{}{"action": "HOLD"})
|
||
if err != nil {
|
||
t.Fatal(err)
|
||
}
|
||
if out != "未知" {
|
||
t.Fatalf("got %q", out)
|
||
}
|
||
}
|