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