feat: support merging multiple subscriptions

This commit is contained in:
2026-07-19 23:58:02 +08:00
parent fb4d927220
commit 087869d84f
17 changed files with 1341 additions and 60 deletions

View File

@ -0,0 +1,163 @@
package automation
import (
"reflect"
"testing"
)
func TestParsePath(t *testing.T) {
cases := map[string][]pathStep{
"dns.nameserver": {mapKeyStep{"dns"}, mapKeyStep{"nameserver"}},
"rules": {mapKeyStep{"rules"}},
"proxy-groups[0].proxies": {mapKeyStep{"proxy-groups"}, indexStep{0}, mapKeyStep{"proxies"}},
"a[0][1]": {mapKeyStep{"a"}, indexStep{0}, indexStep{1}},
}
for path, want := range cases {
got, err := parsePath(path)
if err != nil {
t.Fatalf("parsePath(%q) error = %v", path, err)
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("parsePath(%q) = %#v, want %#v", path, got, want)
}
}
}
func TestParsePath_Invalid(t *testing.T) {
for _, path := range []string{"", "a..b", "a.[b]"} {
if _, err := parsePath(path); err == nil {
t.Fatalf("parsePath(%q): expected error, got nil", path)
}
}
}
func TestApplyPatch_ReplaceExistingKey(t *testing.T) {
root := map[string]interface{}{
"dns": map[string]interface{}{
"nameserver": []interface{}{"114.114.114.114"},
},
}
err := applyPatch(root, PatchRule{Path: "dns.nameserver", Op: "replace", Value: []interface{}{"1.1.1.1"}})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
dns := root["dns"].(map[string]interface{})
if !reflect.DeepEqual(dns["nameserver"], []interface{}{"1.1.1.1"}) {
t.Fatalf("got %#v", dns["nameserver"])
}
}
func TestApplyPatch_AppendToList(t *testing.T) {
root := map[string]interface{}{
"rules": []interface{}{"MATCH,DIRECT"},
}
err := applyPatch(root, PatchRule{Path: "rules", Op: "append", Value: []interface{}{"DOMAIN,foo.com,PROXY"}})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
want := []interface{}{"MATCH,DIRECT", "DOMAIN,foo.com,PROXY"}
if !reflect.DeepEqual(root["rules"], want) {
t.Fatalf("got %#v, want %#v", root["rules"], want)
}
}
func TestApplyPatch_PrependToList(t *testing.T) {
root := map[string]interface{}{
"rules": []interface{}{"MATCH,DIRECT"},
}
err := applyPatch(root, PatchRule{Path: "rules", Op: "prepend", Value: "DOMAIN,foo.com,PROXY"})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
want := []interface{}{"DOMAIN,foo.com,PROXY", "MATCH,DIRECT"}
if !reflect.DeepEqual(root["rules"], want) {
t.Fatalf("got %#v, want %#v", root["rules"], want)
}
}
func TestApplyPatch_AutoVivifyIntermediateMaps(t *testing.T) {
root := map[string]interface{}{}
err := applyPatch(root, PatchRule{Path: "dns.nameserver", Op: "replace", Value: []interface{}{"1.1.1.1"}})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
dns, ok := root["dns"].(map[string]interface{})
if !ok {
t.Fatalf("expected dns to be auto-created as a map, got %#v", root["dns"])
}
if !reflect.DeepEqual(dns["nameserver"], []interface{}{"1.1.1.1"}) {
t.Fatalf("got %#v", dns["nameserver"])
}
}
func TestApplyPatch_AppendCreatesMissingKey(t *testing.T) {
root := map[string]interface{}{}
err := applyPatch(root, PatchRule{Path: "rules", Op: "append", Value: []interface{}{"MATCH,DIRECT"}})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
if !reflect.DeepEqual(root["rules"], []interface{}{"MATCH,DIRECT"}) {
t.Fatalf("got %#v", root["rules"])
}
}
func TestApplyPatch_IndexIntoList(t *testing.T) {
root := map[string]interface{}{
"proxy-groups": []interface{}{
map[string]interface{}{"name": "g1", "proxies": []interface{}{"DIRECT"}},
},
}
err := applyPatch(root, PatchRule{Path: "proxy-groups[0].proxies", Op: "prepend", Value: []interface{}{"REJECT"}})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
groups := root["proxy-groups"].([]interface{})
g0 := groups[0].(map[string]interface{})
want := []interface{}{"REJECT", "DIRECT"}
if !reflect.DeepEqual(g0["proxies"], want) {
t.Fatalf("got %#v, want %#v", g0["proxies"], want)
}
}
func TestApplyPatch_IndexOutOfRange(t *testing.T) {
root := map[string]interface{}{"proxy-groups": []interface{}{}}
err := applyPatch(root, PatchRule{Path: "proxy-groups[0].proxies", Op: "replace", Value: []interface{}{}})
if err == nil {
t.Fatal("expected out-of-range error, got nil")
}
}
func TestApplyPatch_MergeIntoMap(t *testing.T) {
root := map[string]interface{}{
"dns": map[string]interface{}{"enable": true, "listen": "0.0.0.0:53"},
}
err := applyPatch(root, PatchRule{
Path: "dns",
Op: "append",
Value: map[string]interface{}{
"listen": "127.0.0.1:53",
"enhanced-mode": "fake-ip",
},
})
if err != nil {
t.Fatalf("applyPatch() error = %v", err)
}
dns := root["dns"].(map[string]interface{})
if dns["enable"] != true || dns["listen"] != "127.0.0.1:53" || dns["enhanced-mode"] != "fake-ip" {
t.Fatalf("got %#v", dns)
}
}
func TestApplyPatch_UnknownOp(t *testing.T) {
root := map[string]interface{}{"rules": []interface{}{}}
if err := applyPatch(root, PatchRule{Path: "rules", Op: "delete", Value: nil}); err == nil {
t.Fatal("expected error for unknown op, got nil")
}
}
func TestApplyPatch_AppendToScalarErrors(t *testing.T) {
root := map[string]interface{}{"mode": "rule"}
if err := applyPatch(root, PatchRule{Path: "mode", Op: "append", Value: "x"}); err == nil {
t.Fatal("expected error appending to a scalar, got nil")
}
}