package app import ( egressutilpkg "selective-vpn-api/app/egressutil" "testing" ) func TestParseEgressScope(t *testing.T) { tests := []struct { name string in string wantOK bool want egressScopeTarget }{ { name: "adguardvpn", in: "adguardvpn", wantOK: true, want: egressScopeTarget{ Scope: "adguardvpn", Source: "adguardvpn", }, }, { name: "system", in: "system", wantOK: true, want: egressScopeTarget{ Scope: "system", Source: "system", }, }, { name: "transport normalize", in: "transport: SG RealNetns ", wantOK: true, want: egressScopeTarget{ Scope: "transport:sg-realnetns", Source: "transport", SourceID: "sg-realnetns", }, }, { name: "bad scope", in: "transport:", wantOK: false, }, } for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { got, err := parseEgressScope(tc.in) if tc.wantOK && err != nil { t.Fatalf("parseEgressScope(%q) unexpected error: %v", tc.in, err) } if !tc.wantOK { if err == nil { t.Fatalf("parseEgressScope(%q) expected error", tc.in) } return } if got != tc.want { t.Fatalf("parseEgressScope(%q)=%+v want %+v", tc.in, got, tc.want) } }) } } func TestParseEgressIPFromBody(t *testing.T) { tests := []struct { name string in string wantIP string wantOK bool }{ { name: "plain ipv4", in: "203.0.113.10\n", wantIP: "203.0.113.10", wantOK: true, }, { name: "json ip", in: `{"ip":"198.51.100.7"}`, wantIP: "198.51.100.7", wantOK: true, }, { name: "json query", in: `{"query":"2001:db8::1"}`, wantIP: "2001:db8::1", wantOK: true, }, { name: "invalid", in: "not-an-ip", wantOK: false, }, } for _, tc := range tests { tc := tc t.Run(tc.name, func(t *testing.T) { got, err := egressutilpkg.ParseIPFromBody(tc.in) if tc.wantOK && err != nil { t.Fatalf("ParseIPFromBody unexpected error: %v", err) } if !tc.wantOK { if err == nil { t.Fatalf("ParseIPFromBody expected error") } return } if got != tc.wantIP { t.Fatalf("ParseIPFromBody=%q want %q", got, tc.wantIP) } }) } } func TestEgressParseGeoResponse(t *testing.T) { code, name, err := egressutilpkg.ParseGeoResponse(`{"success":true,"country":"Singapore","country_code":"SG"}`) if err != nil { t.Fatalf("unexpected error: %v", err) } if code != "SG" || name != "Singapore" { t.Fatalf("unexpected geo parse result: code=%q name=%q", code, name) } code, name, err = egressutilpkg.ParseGeoResponse(`{"status":"success","country":"Netherlands","countryCode":"NL"}`) if err != nil { t.Fatalf("unexpected ip-api error: %v", err) } if code != "NL" || name != "Netherlands" { t.Fatalf("unexpected ip-api geo parse result: code=%q name=%q", code, name) } if _, _, err := egressutilpkg.ParseGeoResponse(`{"status":"fail","message":"private range"}`); err == nil { t.Fatalf("expected geo parse error for fail status") } } func TestNormalizeCountryCode(t *testing.T) { if got := egressutilpkg.NormalizeCountryCode("sg"); got != "SG" { t.Fatalf("NormalizeCountryCode(sg)=%q", got) } if got := egressutilpkg.NormalizeCountryCode("123"); got != "" { t.Fatalf("NormalizeCountryCode(123) should be empty, got=%q", got) } } func TestEgressResolvedHostForURL(t *testing.T) { host, port, ip := egressutilpkg.ResolvedHostForURL("https://127.0.0.1/ip") if host != "" || port != 0 || ip != "" { t.Fatalf("expected empty resolve tuple for literal IP, got host=%q port=%d ip=%q", host, port, ip) } } func TestEgressParseSingBoxSOCKSProxyURL(t *testing.T) { root := map[string]any{ "inbounds": []any{ map[string]any{ "type": "socks", "listen": "127.0.0.1", "listen_port": 2080, }, }, } got := egressutilpkg.ParseSingBoxSOCKSProxyURL(root) if got != "socks5h://127.0.0.1:2080" { t.Fatalf("unexpected proxy url: %q", got) } root2 := map[string]any{ "inbounds": []any{ map[string]any{ "type": "mixed", "listen": "0.0.0.0", "listen_port": float64(1080), }, }, } got2 := egressutilpkg.ParseSingBoxSOCKSProxyURL(root2) if got2 != "socks5h://127.0.0.1:1080" { t.Fatalf("unexpected mixed proxy url: %q", got2) } }