package proxyconf import "testing" func TestValidate(t *testing.T) { cases := []struct { in string wantErr bool }{ {"", false}, {"http://127.0.0.1:8080", false}, {"https://proxy.corp:3128", false}, {"socks5://127.0.0.1:9050", false}, {"socks5h://127.0.0.1:9050", false}, {"socks5h://user:pass@127.0.0.1:9050", false}, {"ftp://x:21", true}, {"socks4://x:1080", true}, {"not a url", true}, {"://nohost", true}, {"http://", true}, } for _, c := range cases { err := Validate(c.in) if (err != nil) != c.wantErr { t.Errorf("Validate(%q) err=%v wantErr=%v", c.in, err, c.wantErr) } } } func TestBuildDialer_EmptyReturnsDirect(t *testing.T) { d, err := BuildDialer("", nil) if err != nil { t.Fatal(err) } if d == nil { t.Fatal("nil dialer") } } func TestBuildDialer_SOCKS5Accepted(t *testing.T) { d, err := BuildDialer("socks5://127.0.0.1:9050", nil) if err != nil { t.Fatalf("SOCKS5 should construct: %v", err) } if d == nil { t.Fatal("nil dialer") } } func TestBuildDialer_SOCKS5WithAuth(t *testing.T) { d, err := BuildDialer("socks5h://user:pass@127.0.0.1:9050", nil) if err != nil { t.Fatalf("auth SOCKS5 should construct: %v", err) } if d == nil { t.Fatal("nil dialer") } } func TestBuildDialer_HTTPProxyPassthrough(t *testing.T) { // HTTP proxy uses Transport.Proxy; dialer should be direct-equivalent. d, err := BuildDialer("http://127.0.0.1:8080", nil) if err != nil { t.Fatal(err) } if d == nil { t.Fatal("nil dialer") } } func TestBuildDialer_UnsupportedScheme(t *testing.T) { _, err := BuildDialer("ftp://127.0.0.1", nil) if err == nil { t.Error("expected error for unsupported scheme") } } func TestBuildProxyFunc_HTTPProxy(t *testing.T) { fn, err := BuildProxyFunc("http://127.0.0.1:8080") if err != nil { t.Fatal(err) } if fn == nil { t.Fatal("http:// should yield non-nil ProxyFunc") } } func TestBuildProxyFunc_SOCKSReturnsNil(t *testing.T) { fn, err := BuildProxyFunc("socks5://127.0.0.1:9050") if err != nil { t.Fatal(err) } if fn != nil { t.Error("SOCKS5 should return nil ProxyFunc (handled by dialer)") } } func TestBuildProxyFunc_EmptyReturnsNil(t *testing.T) { fn, err := BuildProxyFunc("") if err != nil || fn != nil { t.Errorf("empty → (nil, nil), got (%v, %v)", fn, err) } } func TestHumanize(t *testing.T) { cases := map[string]string{ "": "direct (no proxy)", "http://proxy.corp:3128": "http://proxy.corp:3128", "socks5://127.0.0.1:9050": "socks5://127.0.0.1:9050", "socks5h://user:secret@10.0.0.1:443": "socks5h://(auth)@10.0.0.1:443", } for in, want := range cases { if got := Humanize(in); got != want { t.Errorf("Humanize(%q) = %q, want %q", in, got, want) } } } func TestHumanize_LeaksNoCredentials(t *testing.T) { const secret = "supersecret" h := Humanize("socks5://user:" + secret + "@127.0.0.1:9050") if contains(h, secret) { t.Errorf("Humanize leaked credentials: %s", h) } } func contains(s, sub string) bool { for i := 0; i+len(sub) <= len(s); i++ { if s[i:i+len(sub)] == sub { return true } } return false }