Copilot commented on code in PR #3130:
URL: https://github.com/apache/dubbo-go/pull/3130#discussion_r2638198445


##########
common/rpc_service_test.go:
##########
@@ -251,3 +251,387 @@ func TestGetReference(t *testing.T) {
        ref5 := GetReference(s5)
        assert.Equal(t, expectedReference, ref5)
 }
+
+// Additional tests for better coverage
+
+func TestServiceMethods(t *testing.T) {
+       s := &TestService{}
+       _, err := ServiceMap.Register("TestServiceMethods", testProtocol, 
"group1", "v1", s)
+       assert.NoError(t, err)
+
+       service := ServiceMap.GetService(testProtocol, "TestServiceMethods", 
"group1", "v1")
+       assert.NotNil(t, service)
+
+       // Test Service.Method()
+       methods := service.Method()
+       assert.NotNil(t, methods)
+       assert.True(t, len(methods) > 0)
+
+       // Test Service.Name()
+       assert.Equal(t, "group1/TestServiceMethods:v1", service.Name())
+
+       // Test Service.ServiceType()
+       svcType := service.ServiceType()
+       assert.NotNil(t, svcType)
+       assert.Equal(t, "*common.TestService", svcType.String())
+
+       // Test Service.Service()
+       svcValue := service.Service()
+       assert.True(t, svcValue.IsValid())
+
+       // Cleanup
+       ServiceMap.UnRegister("TestServiceMethods", testProtocol, 
ServiceKey("TestServiceMethods", "group1", "v1"))
+}
+
+func TestGetServiceByServiceKey(t *testing.T) {
+       s := &TestService{}
+       _, err := ServiceMap.Register("TestGetServiceByKey", testProtocol, "", 
"v1", s)
+       assert.NoError(t, err)
+
+       // Test GetServiceByServiceKey - found
+       serviceKey := ServiceKey("TestGetServiceByKey", "", "v1")
+       service := ServiceMap.GetServiceByServiceKey(testProtocol, serviceKey)
+       assert.NotNil(t, service)
+
+       // Test GetServiceByServiceKey - protocol not found
+       service = ServiceMap.GetServiceByServiceKey("nonexistent", serviceKey)
+       assert.Nil(t, service)
+
+       // Test GetServiceByServiceKey - service key not found
+       service = ServiceMap.GetServiceByServiceKey(testProtocol, 
"nonexistent:v1")
+       assert.Nil(t, service)
+
+       // Cleanup
+       ServiceMap.UnRegister("TestGetServiceByKey", testProtocol, serviceKey)
+}
+
+func TestGetInterface(t *testing.T) {
+       s := &TestService{}
+       _, err := ServiceMap.Register("TestGetInterface", testProtocol, "", 
"v1", s)
+       assert.NoError(t, err)
+
+       // Test GetInterface - found
+       services := ServiceMap.GetInterface("TestGetInterface")
+       assert.NotNil(t, services)
+       assert.Equal(t, 1, len(services))
+
+       // Test GetInterface - not found
+       services = ServiceMap.GetInterface("nonexistent")
+       assert.Nil(t, services)
+
+       // Cleanup
+       ServiceMap.UnRegister("TestGetInterface", testProtocol, 
ServiceKey("TestGetInterface", "", "v1"))
+}
+
+func TestMethodTypeSuiteContextInvalid(t *testing.T) {
+       mt := &MethodType{ctxType: 
reflect.TypeOf((*context.Context)(nil)).Elem()}
+
+       // Test with nil context (invalid)
+       var nilCtx context.Context = nil
+       result := mt.SuiteContext(nilCtx)
+       assert.True(t, result.IsValid())
+       assert.True(t, result.IsZero())
+}
+
+func TestIsExported(t *testing.T) {
+       assert.True(t, isExported("Exported"))
+       assert.True(t, isExported("A"))
+       assert.False(t, isExported("unexported"))
+       assert.False(t, isExported("a"))
+       assert.False(t, isExported(""))
+}
+
+func TestIsExportedOrBuiltinType(t *testing.T) {
+       // Exported type
+       assert.True(t, isExportedOrBuiltinType(reflect.TypeOf(TestService{})))
+
+       // Pointer to exported type
+       assert.True(t, isExportedOrBuiltinType(reflect.TypeOf(&TestService{})))
+
+       // Builtin type (string)
+       assert.True(t, isExportedOrBuiltinType(reflect.TypeOf("")))
+
+       // Builtin type (int)
+       assert.True(t, isExportedOrBuiltinType(reflect.TypeOf(0)))
+
+       // Pointer to builtin
+       var i int
+       assert.True(t, isExportedOrBuiltinType(reflect.TypeOf(&i)))
+
+       // Unexported type
+       assert.False(t, isExportedOrBuiltinType(reflect.TypeOf(testService{})))
+}
+
+// Test service with XXX prefix methods (should be skipped)
+type TestServiceWithXXX struct{}
+
+func (s *TestServiceWithXXX) XXX_InterfaceName() string {
+       return "test"
+}
+
+func (s *TestServiceWithXXX) NormalMethod(ctx context.Context) error {
+       return nil
+}
+
+func (s *TestServiceWithXXX) Reference() string {
+       return "TestServiceWithXXX"
+}
+
+func TestSuiteMethodSkipsXXXPrefix(t *testing.T) {
+       s := &TestServiceWithXXX{}
+       sType := reflect.TypeOf(s)
+
+       // XXX_ prefixed method should be skipped
+       method, ok := sType.MethodByName("XXX_InterfaceName")
+       assert.True(t, ok)
+       mt := suiteMethod(method)
+       assert.Nil(t, mt)
+
+       // Reference method should be skipped
+       method, ok = sType.MethodByName("Reference")
+       assert.True(t, ok)
+       mt = suiteMethod(method)
+       assert.Nil(t, mt)
+
+       // Normal method should not be skipped
+       method, ok = sType.MethodByName("NormalMethod")
+       assert.True(t, ok)
+       mt = suiteMethod(method)
+       assert.NotNil(t, mt)
+}
+
+// Test service with SetGRPCServer method
+type TestServiceWithGRPC struct{}
+
+func (s *TestServiceWithGRPC) SetGRPCServer(server any) {}
+
+func (s *TestServiceWithGRPC) ValidMethod(ctx context.Context, arg any) error {
+       return nil
+}
+
+func TestSuiteMethodSkipsSetGRPCServer(t *testing.T) {
+       s := &TestServiceWithGRPC{}
+       sType := reflect.TypeOf(s)
+
+       // SetGRPCServer should be skipped
+       method, ok := sType.MethodByName("SetGRPCServer")
+       assert.True(t, ok)
+       mt := suiteMethod(method)
+       assert.Nil(t, mt)
+}
+
+func TestGetReferenceWithStruct(t *testing.T) {
+       // Test with struct (not pointer)
+       s := TestService{}
+       ref := GetReference(s)
+       assert.Equal(t, "TestService", ref)
+}
+
+func TestGetReferenceWithAnonymousStruct(t *testing.T) {
+       // Anonymous struct embedded in pointer
+       s := &struct {
+               ServiceWithoutRef
+       }{}
+       ref := GetReference(s)
+       assert.Equal(t, "ServiceWithoutRef", ref)
+}
+
+func TestRegisterWithEmptyServiceName(t *testing.T) {
+       // This tests the edge case where service name cannot be determined
+       // Using a non-struct type
+       var fn func()
+       _, err := ServiceMap.Register("test", "proto", "", "v1", fn)
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "no service name")
+}
+
+func TestUnRegisterInterfaceNotFound(t *testing.T) {
+       s := &TestService{}
+       _, err := ServiceMap.Register("TestUnRegisterInterface", testProtocol, 
"", "v1", s)
+       assert.NoError(t, err)
+
+       // Manually remove from interfaceMap to simulate inconsistent state
+       ServiceMap.mutex.Lock()
+       delete(ServiceMap.interfaceMap, "TestUnRegisterInterface")
+       ServiceMap.mutex.Unlock()
+
+       err = ServiceMap.UnRegister("TestUnRegisterInterface", testProtocol, 
ServiceKey("TestUnRegisterInterface", "", "v1"))
+       assert.Error(t, err)
+       assert.Contains(t, err.Error(), "no service for 
TestUnRegisterInterface")
+
+       // Cleanup
+       ServiceMap.mutex.Lock()
+       delete(ServiceMap.serviceMap[testProtocol], 
ServiceKey("TestUnRegisterInterface", "", "v1"))
+       ServiceMap.mutex.Unlock()
+}

Review Comment:
   This test manually manipulates the ServiceMap's internal state 
(interfaceMap) and then relies on manual cleanup of serviceMap. This creates 
test interdependencies and potential test pollution. If the cleanup fails or 
the test panics before cleanup, subsequent tests may be affected. Consider 
using a dedicated test instance or a more robust cleanup mechanism like defer 
or t.Cleanup().



##########
common/config/environment_test.go:
##########
@@ -75,3 +76,66 @@ func TestInmemoryConfigurationGetSubProperty(t *testing.T) {
 
        assert.Equal(t, struct{}{}, m["123"])
 }
+
+func TestNewEnvInstance(t *testing.T) {
+       // Reset instance
+       oldInstance := instance
+       defer func() { instance = oldInstance }()
+
+       NewEnvInstance()
+       assert.NotNil(t, instance)
+       assert.True(t, instance.configCenterFirst)
+}
+
+func TestSetAndGetDynamicConfiguration(t *testing.T) {
+       env := GetEnvInstance()
+
+       // Initially nil
+       assert.Nil(t, env.GetDynamicConfiguration())
+
+       // Set and get
+       // Using nil as mock since we just test the setter/getter
+       env.SetDynamicConfiguration(nil)
+       assert.Nil(t, env.GetDynamicConfiguration())
+}

Review Comment:
   The test comment states "Initially nil" but doesn't verify the initial state 
before the SetDynamicConfiguration call. While the assertion on line 94 does 
check for nil, this might be testing the state after a previous test rather 
than the truly initial state. Consider adding cleanup in the test setup or 
verifying this is testing the intended scenario.



##########
common/url_test.go:
##########
@@ -648,3 +651,695 @@ func TestURLSetParamsMultiValue(t *testing.T) {
        got3 := u2.GetParams()["only_empty"]
        assert.ElementsMatch(t, []string{""}, got3)
 }
+
+func TestRoleType(t *testing.T) {
+       assert.Equal(t, "consumers", RoleType(CONSUMER).String())
+       assert.Equal(t, "configurators", RoleType(CONFIGURATOR).String())
+       assert.Equal(t, "routers", RoleType(ROUTER).String())
+       assert.Equal(t, "providers", RoleType(PROVIDER).String())
+
+       assert.Equal(t, "consumer", RoleType(CONSUMER).Role())
+       assert.Equal(t, "", RoleType(CONFIGURATOR).Role())
+       assert.Equal(t, "routers", RoleType(ROUTER).Role())
+       assert.Equal(t, "provider", RoleType(PROVIDER).Role())
+}
+
+func TestJavaClassName(t *testing.T) {
+       u := &URL{}
+       assert.Equal(t, "org.apache.dubbo.common.URL", u.JavaClassName())
+}
+
+func TestWithInterface(t *testing.T) {
+       u := NewURLWithOptions(WithInterface("com.test.Service"))
+       assert.Equal(t, "com.test.Service", u.GetParam(constant.InterfaceKey, 
""))
+}
+
+func TestWithLocation(t *testing.T) {
+       // WithLocation sets Location, but NewURLWithOptions overwrites it with 
Ip:Port
+       // So we need to set Ip and Port as well, or test the option directly
+       u := &URL{}
+       WithLocation("192.168.1.1:8080")(u)
+       assert.Equal(t, "192.168.1.1:8080", u.Location)
+
+       // When using NewURLWithOptions with Ip and Port
+       u2 := NewURLWithOptions(WithIp("192.168.1.1"), WithPort("8080"))
+       assert.Equal(t, "192.168.1.1:8080", u2.Location)
+}
+
+func TestWithToken(t *testing.T) {
+       // empty token
+       u1 := NewURLWithOptions(WithToken(""))
+       assert.Equal(t, "", u1.GetParam(constant.TokenKey, ""))
+
+       // custom token
+       u2 := NewURLWithOptions(WithToken("my-token"))
+       assert.Equal(t, "my-token", u2.GetParam(constant.TokenKey, ""))
+
+       // "true" generates UUID
+       u3 := NewURLWithOptions(WithToken("true"))
+       token := u3.GetParam(constant.TokenKey, "")
+       assert.NotEmpty(t, token)
+       assert.NotEqual(t, "true", token)
+
+       // "default" generates UUID
+       u4 := NewURLWithOptions(WithToken("default"))
+       token2 := u4.GetParam(constant.TokenKey, "")
+       assert.NotEmpty(t, token2)
+       assert.NotEqual(t, "default", token2)
+
+       // "TRUE" (uppercase) generates UUID
+       u5 := NewURLWithOptions(WithToken("TRUE"))
+       token3 := u5.GetParam(constant.TokenKey, "")
+       assert.NotEmpty(t, token3)
+       assert.NotEqual(t, "TRUE", token3)
+}
+
+func TestWithWeight(t *testing.T) {
+       // positive weight
+       u1 := NewURLWithOptions(WithWeight(100))
+       assert.Equal(t, "100", u1.GetParam(constant.WeightKey, ""))
+
+       // zero weight (should not be set)
+       u2 := NewURLWithOptions(WithWeight(0))
+       assert.Equal(t, "", u2.GetParam(constant.WeightKey, ""))
+
+       // negative weight (should not be set)
+       u3 := NewURLWithOptions(WithWeight(-1))
+       assert.Equal(t, "", u3.GetParam(constant.WeightKey, ""))
+}
+
+func TestMatchKey(t *testing.T) {
+       assert.Equal(t, "com.test.Service:dubbo", MatchKey("com.test.Service", 
"dubbo"))
+       assert.Equal(t, ":http", MatchKey("", "http"))
+}
+
+func TestURLGroupInterfaceVersion(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=test-group&version=1.0.0")
+       assert.Equal(t, "test-group", u.Group())
+       assert.Equal(t, "com.test.Service", u.Interface())
+       assert.Equal(t, "1.0.0", u.Version())
+}
+
+func TestURLAddress(t *testing.T) {
+       u1 := &URL{Ip: "192.168.1.1", Port: "8080"}
+       assert.Equal(t, "192.168.1.1:8080", u1.Address())
+
+       u2 := &URL{Ip: "192.168.1.1", Port: ""}
+       assert.Equal(t, "192.168.1.1", u2.Address())
+}
+
+func TestURLKey(t *testing.T) {
+       u, _ := 
NewURL("dubbo://user:[email protected]:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0")
+       key := u.Key()
+       assert.Contains(t, key, "dubbo://")
+       assert.Contains(t, key, "user:pass@")
+       assert.Contains(t, key, "interface=com.test.Service")
+       assert.Contains(t, key, "group=g1")
+       assert.Contains(t, key, "version=1.0")
+}
+
+func TestGetCacheInvokerMapKey(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0&timestamp=12345")
+       key := u.GetCacheInvokerMapKey()
+       assert.Contains(t, key, "interface=com.test.Service")
+       assert.Contains(t, key, "group=g1")
+       assert.Contains(t, key, "version=1.0")
+       assert.Contains(t, key, "timestamp=12345")
+}
+
+func TestServiceKey(t *testing.T) {
+       // with group and version
+       assert.Equal(t, "group/interface:version", ServiceKey("interface", 
"group", "version"))
+
+       // without group
+       assert.Equal(t, "interface:version", ServiceKey("interface", "", 
"version"))
+
+       // without version
+       assert.Equal(t, "group/interface", ServiceKey("interface", "group", ""))
+
+       // version 0.0.0 should be ignored
+       assert.Equal(t, "group/interface", ServiceKey("interface", "group", 
"0.0.0"))
+
+       // empty interface
+       assert.Equal(t, "", ServiceKey("", "group", "version"))
+
+       // URL method
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0")
+       assert.Equal(t, "g1/com.test.Service:1.0", u.ServiceKey())
+}
+
+func TestEncodedServiceKey(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0")
+       encoded := u.EncodedServiceKey()
+       assert.Equal(t, "g1*com.test.Service:1.0", encoded)
+}
+
+func TestServiceWithSubURL(t *testing.T) {
+       subURL, _ := NewURL("dubbo://127.0.0.1:20000?interface=com.sub.Service")
+       u := &URL{SubURL: subURL}
+       assert.Equal(t, "com.sub.Service", u.Service())
+
+       // empty SubURL interface
+       subURL2 := &URL{}
+       u2 := &URL{SubURL: subURL2, Path: "/com.path.Service"}
+       assert.Equal(t, "com.path.Service", u2.Service())
+
+       // no SubURL, no interface param
+       u3 := &URL{Path: "/com.path.Service"}
+       assert.Equal(t, "com.path.Service", u3.Service())
+}
+
+func TestAddParam(t *testing.T) {
+       u := &URL{}
+       u.AddParam("key1", "value1")
+       assert.Equal(t, "value1", u.GetParam("key1", ""))
+
+       // add another value to same key
+       u.AddParam("key1", "value2")
+       params := u.GetParams()
+       assert.Equal(t, 2, len(params["key1"]))
+}
+
+func TestAddParamAvoidNil(t *testing.T) {
+       u := &URL{}
+       u.AddParamAvoidNil("key1", "value1")
+       assert.Equal(t, "value1", u.GetParam("key1", ""))
+}
+
+func TestDelParam(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1&key2=value2")
+       u.DelParam("key1")
+       assert.Equal(t, "", u.GetParam("key1", ""))
+       assert.Equal(t, "value2", u.GetParam("key2", ""))
+
+       // delete from nil params
+       u2 := &URL{}
+       u2.DelParam("key") // should not panic
+}
+
+func TestGetNonDefaultParam(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1")
+
+       v, ok := u.GetNonDefaultParam("key1")
+       assert.True(t, ok)
+       assert.Equal(t, "value1", v)
+
+       v, ok = u.GetNonDefaultParam("nonexistent")
+       assert.False(t, ok)
+       assert.Equal(t, "", v)
+}
+
+func TestRangeParams(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1&key2=value2")
+       count := 0
+       u.RangeParams(func(key, value string) bool {
+               count++
+               return true
+       })
+       assert.Equal(t, 2, count)
+
+       // test early break
+       count = 0
+       u.RangeParams(func(key, value string) bool {
+               count++
+               return false // break after first
+       })
+       assert.Equal(t, 1, count)
+}
+
+func TestGetParamInt32(t *testing.T) {
+       params := url.Values{}
+       params.Set("key", "123")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       v := u.GetParamInt32("key", 0)
+       assert.Equal(t, int32(123), v)
+
+       // invalid value
+       u2 := &URL{}
+       v2 := u2.GetParamInt32("key", 99)
+       assert.Equal(t, int32(99), v2)
+}
+
+func TestGetParamByIntValue(t *testing.T) {
+       params := url.Values{}
+       params.Set("key", "456")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       v := u.GetParamByIntValue("key", 0)
+       assert.Equal(t, 456, v)
+
+       // invalid value
+       u2 := &URL{}
+       v2 := u2.GetParamByIntValue("key", 99)
+       assert.Equal(t, 99, v2)
+}
+
+func TestGetMethodParamIntValue(t *testing.T) {
+       params := url.Values{}
+       params.Set("methods.GetValue.timeout", "100")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       v := u.GetMethodParamIntValue("GetValue", "timeout", 0)
+       assert.Equal(t, 100, v)
+
+       // missing method param
+       v2 := u.GetMethodParamIntValue("OtherMethod", "timeout", 50)
+       assert.Equal(t, 50, v2)
+}
+
+func TestGetMethodParamInt64(t *testing.T) {
+       params := url.Values{}
+       params.Set("methods.GetValue.timeout", "200")
+       params.Set("timeout", "100")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       // method param exists
+       v := u.GetMethodParamInt64("GetValue", "timeout", 0)
+       assert.Equal(t, int64(200), v)
+
+       // method param not exists, fallback to global
+       v2 := u.GetMethodParamInt64("OtherMethod", "timeout", 0)
+       assert.Equal(t, int64(100), v2)
+
+       // neither exists
+       v3 := u.GetMethodParamInt64("OtherMethod", "retries", 5)
+       assert.Equal(t, int64(5), v3)
+}
+
+func TestGetParamDuration(t *testing.T) {
+       params := url.Values{}
+       params.Set("timeout", "5s")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       d := u.GetParamDuration("timeout", "1s")
+       assert.Equal(t, 5*time.Second, d)
+
+       // invalid duration, returns 3s default
+       params2 := url.Values{}
+       params2.Set("timeout", "invalid")
+       u2 := &URL{}
+       u2.SetParams(params2)
+       d2 := u2.GetParamDuration("timeout", "invalid")
+       assert.Equal(t, 3*time.Second, d2)
+
+       // missing param with valid default
+       u3 := &URL{}
+       d3 := u3.GetParamDuration("timeout", "2s")
+       assert.Equal(t, 2*time.Second, d3)
+}
+
+func TestCloneExceptParams(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2&key3=value3")
+
+       excludeSet := gxset.NewSet("key1", "key3")
+       cloned := u.CloneExceptParams(excludeSet)
+
+       assert.Equal(t, "", cloned.GetParam("key1", ""))
+       assert.Equal(t, "value2", cloned.GetParam("key2", ""))
+       assert.Equal(t, "", cloned.GetParam("key3", ""))
+       assert.Equal(t, "dubbo", cloned.Protocol)
+}
+
+func TestCloneWithParams(t *testing.T) {
+       u, _ := 
NewURL("dubbo://user:[email protected]:20000/com.test.Service?key1=value1&key2=value2&key3=value3")
+       u.Methods = []string{"method1", "method2"}
+
+       cloned := u.CloneWithParams([]string{"key1", "key3"})
+
+       assert.Equal(t, "value1", cloned.GetParam("key1", ""))
+       assert.Equal(t, "", cloned.GetParam("key2", ""))
+       assert.Equal(t, "value3", cloned.GetParam("key3", ""))
+       assert.Equal(t, "dubbo", cloned.Protocol)
+       assert.Equal(t, "user", cloned.Username)
+       assert.Equal(t, "pass", cloned.Password)
+       assert.Equal(t, []string{"method1", "method2"}, cloned.Methods)
+}
+
+func TestURLCompare(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000/a.Service")
+       u2, _ := NewURL("dubbo://127.0.0.1:20000/b.Service")
+       u3, _ := NewURL("dubbo://127.0.0.1:20000/a.Service")
+
+       assert.Equal(t, -1, u1.Compare(u2))
+       assert.Equal(t, 1, u2.Compare(u1))
+       assert.Equal(t, 0, u1.Compare(u3))
+}
+
+func TestRangeAttributes(t *testing.T) {
+       u := &URL{}
+       u.SetAttribute("attr1", "value1")
+       u.SetAttribute("attr2", 123)
+
+       count := 0
+       u.RangeAttributes(func(key string, value any) bool {
+               count++
+               return true
+       })
+       assert.Equal(t, 2, count)
+
+       // test early break
+       count = 0
+       u.RangeAttributes(func(key string, value any) bool {
+               count++
+               return false
+       })
+       assert.Equal(t, 1, count)
+}
+
+func TestURLSlice(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000/c.Service")
+       u2, _ := NewURL("dubbo://127.0.0.1:20000/a.Service")
+       u3, _ := NewURL("dubbo://127.0.0.1:20000/b.Service")
+
+       slice := URLSlice{u1, u2, u3}
+
+       assert.Equal(t, 3, slice.Len())
+       assert.True(t, slice.Less(1, 2))  // a < b
+       assert.False(t, slice.Less(0, 2)) // c > b
+
+       slice.Swap(0, 1)
+       assert.Equal(t, u2, slice[0])
+       assert.Equal(t, u1, slice[1])
+}
+
+func TestIsEquals(t *testing.T) {
+       u1, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2")
+       u2, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2")
+       u3, _ := 
NewURL("dubbo://127.0.0.1:20001/com.test.Service?key1=value1&key2=value2")
+       u4, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=different")
+
+       // equal URLs
+       assert.True(t, IsEquals(u1, u2))
+
+       // different port
+       assert.False(t, IsEquals(u1, u3))
+
+       // different param value
+       assert.False(t, IsEquals(u1, u4))
+
+       // with excludes
+       assert.True(t, IsEquals(u1, u4, "key2"))
+
+       // nil checks
+       assert.False(t, IsEquals(nil, u1))
+       assert.False(t, IsEquals(u1, nil))
+}
+
+func TestGetSubscribeName(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000?interface=com.test.Service&version=1.0&group=test")
+       name := GetSubscribeName(u)
+       assert.Contains(t, name, "providers")
+       assert.Contains(t, name, "com.test.Service")
+       assert.Contains(t, name, "1.0")
+       assert.Contains(t, name, "test")
+}
+
+func TestNewURLEmptyString(t *testing.T) {
+       u, err := NewURL("")
+       assert.NoError(t, err)
+       assert.NotNil(t, u)
+       assert.Equal(t, "", u.Protocol)
+}
+
+func TestNewURLWithUsernamePassword(t *testing.T) {
+       u, err := 
NewURL("dubbo://admin:[email protected]:20000/com.test.Service")
+       assert.NoError(t, err)
+       assert.Equal(t, "admin", u.Username)
+       assert.Equal(t, "secret", u.Password)
+}
+
+func TestURLStringWithCredentials(t *testing.T) {
+       u, _ := 
NewURL("dubbo://admin:[email protected]:20000/com.test.Service?key=value")
+       str := u.String()
+       assert.Contains(t, str, "admin:secret@")
+}
+
+func TestToMapWithoutPort(t *testing.T) {
+       u := &URL{
+               Protocol: "dubbo",
+               Location: "127.0.0.1",
+               Path:     "/com.test.Service",
+       }
+       m := u.ToMap()
+       assert.Equal(t, "0", m["port"])
+}
+
+func TestToMapEmpty(t *testing.T) {
+       u := &URL{}
+       m := u.ToMap()
+       assert.Nil(t, m)
+}
+
+func TestMergeURLWithAttributes(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1")
+       u1.SetAttribute("attr1", "attrValue1")
+
+       u2, _ := NewURL("dubbo://127.0.0.1:20001?key2=value2")
+       u2.SetAttribute("attr2", "attrValue2")
+       u2.Methods = []string{"method1"}
+
+       merged := u1.MergeURL(u2)
+
+       // attributes should be merged
+       v1, ok1 := merged.GetAttribute("attr1")
+       assert.True(t, ok1)
+       assert.Equal(t, "attrValue1", v1)
+
+       v2, ok2 := merged.GetAttribute("attr2")
+       assert.True(t, ok2)
+       assert.Equal(t, "attrValue2", v2)
+}
+
+func TestURLEqualWithCategory(t *testing.T) {
+       // test category matching with RemoveValuePrefix
+       u1, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&category=providers")
+       u2, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&category=-providers")
+       assert.False(t, u1.URLEqual(u2))
+
+       // category contains target - u3 has category that contains u1's 
category
+       u3, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&category=providers,consumers")
+       // u1 checks if u3's category matches - u3 has "providers,consumers" 
which contains "providers"
+       assert.True(t, u3.URLEqual(u1))
+}
+
+func TestNewURLWithRegistryGroup(t *testing.T) {
+       u, err := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?registry.group=mygroup")
+       assert.NoError(t, err)
+       assert.Contains(t, u.PrimitiveURL, "mygroup")
+}
+
+func TestColonSeparatedKeyEmpty(t *testing.T) {
+       u := &URL{}
+       assert.Equal(t, "", u.ColonSeparatedKey())
+}
+
+func TestColonSeparatedKeyWithVersion000(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000")
+       u.AddParam(constant.InterfaceKey, "com.test.Service")
+       u.AddParam(constant.VersionKey, "0.0.0")
+       u.AddParam(constant.GroupKey, "group1")
+
+       // version 0.0.0 should be treated as empty
+       assert.Equal(t, "com.test.Service::group1", u.ColonSeparatedKey())
+}
+
+// Additional edge case tests for better coverage
+
+func TestNewURLParseError(t *testing.T) {
+       // Test invalid URL that causes parse error
+       _, err := NewURL("://invalid")
+       assert.Error(t, err)
+}
+
+func TestNewURLWithInvalidQuery(t *testing.T) {
+       // URL with special characters that need escaping
+       u, err := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key=value%20with%20space")
+       assert.NoError(t, err)
+       assert.Equal(t, "value with space", u.GetParam("key", ""))
+}
+
+func TestURLStringWithoutCredentials(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000/com.test.Service?key=value")
+       str := u.String()
+       assert.Contains(t, str, "dubbo://127.0.0.1:20000")
+       assert.NotContains(t, str, "@")
+}
+
+func TestGetParamAndDecodedError(t *testing.T) {
+       u := &URL{}
+       params := url.Values{}
+       params.Set("rule", "invalid-base64!!!")
+       u.SetParams(params)
+
+       _, err := u.GetParamAndDecoded("rule")
+       assert.Error(t, err)
+}
+
+func TestIsEqualsWithDifferentMapLength(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1")
+       u2, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2")
+       assert.False(t, IsEquals(u1, u2))
+}
+
+func TestIsEqualsWithMissingKey(t *testing.T) {
+       u1, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2")
+       u2, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key3=value3")
+       assert.False(t, IsEquals(u1, u2))
+}
+
+func TestIsEqualsBothNil(t *testing.T) {
+       // Both nil should not panic - but current implementation would panic
+       // This tests the nil check logic
+       var u1 *URL = nil
+       var u2 *URL = nil
+       // Note: IsEquals(nil, nil) would panic due to nil pointer dereference
+       // This is expected behavior based on current implementation

Review Comment:
   The comment on lines 1202-1207 mentions that "IsEquals(nil, nil) would 
panic" and describes it as "expected behavior," but the test doesn't actually 
test this scenario. The test only checks one nil and one non-nil URL. Either 
the comment should be updated to reflect what the test actually does, or the 
test should be removed if the panic behavior with both nil arguments is indeed 
expected and doesn't need testing.
   ```suggestion
        // Verify that IsEquals handles cases where exactly one URL is nil 
without panicking.
        // Note: the behavior when both arguments are nil (IsEquals(nil, nil)) 
is not covered here.
        var u1 *URL = nil
        var u2 *URL = nil
   ```



##########
common/url_test.go:
##########
@@ -648,3 +651,695 @@ func TestURLSetParamsMultiValue(t *testing.T) {
        got3 := u2.GetParams()["only_empty"]
        assert.ElementsMatch(t, []string{""}, got3)
 }
+
+func TestRoleType(t *testing.T) {
+       assert.Equal(t, "consumers", RoleType(CONSUMER).String())
+       assert.Equal(t, "configurators", RoleType(CONFIGURATOR).String())
+       assert.Equal(t, "routers", RoleType(ROUTER).String())
+       assert.Equal(t, "providers", RoleType(PROVIDER).String())
+
+       assert.Equal(t, "consumer", RoleType(CONSUMER).Role())
+       assert.Equal(t, "", RoleType(CONFIGURATOR).Role())
+       assert.Equal(t, "routers", RoleType(ROUTER).Role())
+       assert.Equal(t, "provider", RoleType(PROVIDER).Role())
+}
+
+func TestJavaClassName(t *testing.T) {
+       u := &URL{}
+       assert.Equal(t, "org.apache.dubbo.common.URL", u.JavaClassName())
+}
+
+func TestWithInterface(t *testing.T) {
+       u := NewURLWithOptions(WithInterface("com.test.Service"))
+       assert.Equal(t, "com.test.Service", u.GetParam(constant.InterfaceKey, 
""))
+}
+
+func TestWithLocation(t *testing.T) {
+       // WithLocation sets Location, but NewURLWithOptions overwrites it with 
Ip:Port
+       // So we need to set Ip and Port as well, or test the option directly
+       u := &URL{}
+       WithLocation("192.168.1.1:8080")(u)
+       assert.Equal(t, "192.168.1.1:8080", u.Location)
+
+       // When using NewURLWithOptions with Ip and Port
+       u2 := NewURLWithOptions(WithIp("192.168.1.1"), WithPort("8080"))
+       assert.Equal(t, "192.168.1.1:8080", u2.Location)
+}
+
+func TestWithToken(t *testing.T) {
+       // empty token
+       u1 := NewURLWithOptions(WithToken(""))
+       assert.Equal(t, "", u1.GetParam(constant.TokenKey, ""))
+
+       // custom token
+       u2 := NewURLWithOptions(WithToken("my-token"))
+       assert.Equal(t, "my-token", u2.GetParam(constant.TokenKey, ""))
+
+       // "true" generates UUID
+       u3 := NewURLWithOptions(WithToken("true"))
+       token := u3.GetParam(constant.TokenKey, "")
+       assert.NotEmpty(t, token)
+       assert.NotEqual(t, "true", token)
+
+       // "default" generates UUID
+       u4 := NewURLWithOptions(WithToken("default"))
+       token2 := u4.GetParam(constant.TokenKey, "")
+       assert.NotEmpty(t, token2)
+       assert.NotEqual(t, "default", token2)
+
+       // "TRUE" (uppercase) generates UUID
+       u5 := NewURLWithOptions(WithToken("TRUE"))
+       token3 := u5.GetParam(constant.TokenKey, "")
+       assert.NotEmpty(t, token3)
+       assert.NotEqual(t, "TRUE", token3)
+}
+
+func TestWithWeight(t *testing.T) {
+       // positive weight
+       u1 := NewURLWithOptions(WithWeight(100))
+       assert.Equal(t, "100", u1.GetParam(constant.WeightKey, ""))
+
+       // zero weight (should not be set)
+       u2 := NewURLWithOptions(WithWeight(0))
+       assert.Equal(t, "", u2.GetParam(constant.WeightKey, ""))
+
+       // negative weight (should not be set)
+       u3 := NewURLWithOptions(WithWeight(-1))
+       assert.Equal(t, "", u3.GetParam(constant.WeightKey, ""))
+}
+
+func TestMatchKey(t *testing.T) {
+       assert.Equal(t, "com.test.Service:dubbo", MatchKey("com.test.Service", 
"dubbo"))
+       assert.Equal(t, ":http", MatchKey("", "http"))
+}
+
+func TestURLGroupInterfaceVersion(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=test-group&version=1.0.0")
+       assert.Equal(t, "test-group", u.Group())
+       assert.Equal(t, "com.test.Service", u.Interface())
+       assert.Equal(t, "1.0.0", u.Version())
+}
+
+func TestURLAddress(t *testing.T) {
+       u1 := &URL{Ip: "192.168.1.1", Port: "8080"}
+       assert.Equal(t, "192.168.1.1:8080", u1.Address())
+
+       u2 := &URL{Ip: "192.168.1.1", Port: ""}
+       assert.Equal(t, "192.168.1.1", u2.Address())
+}
+
+func TestURLKey(t *testing.T) {
+       u, _ := 
NewURL("dubbo://user:[email protected]:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0")
+       key := u.Key()
+       assert.Contains(t, key, "dubbo://")
+       assert.Contains(t, key, "user:pass@")
+       assert.Contains(t, key, "interface=com.test.Service")
+       assert.Contains(t, key, "group=g1")
+       assert.Contains(t, key, "version=1.0")
+}
+
+func TestGetCacheInvokerMapKey(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0&timestamp=12345")
+       key := u.GetCacheInvokerMapKey()
+       assert.Contains(t, key, "interface=com.test.Service")
+       assert.Contains(t, key, "group=g1")
+       assert.Contains(t, key, "version=1.0")
+       assert.Contains(t, key, "timestamp=12345")
+}
+
+func TestServiceKey(t *testing.T) {
+       // with group and version
+       assert.Equal(t, "group/interface:version", ServiceKey("interface", 
"group", "version"))
+
+       // without group
+       assert.Equal(t, "interface:version", ServiceKey("interface", "", 
"version"))
+
+       // without version
+       assert.Equal(t, "group/interface", ServiceKey("interface", "group", ""))
+
+       // version 0.0.0 should be ignored
+       assert.Equal(t, "group/interface", ServiceKey("interface", "group", 
"0.0.0"))
+
+       // empty interface
+       assert.Equal(t, "", ServiceKey("", "group", "version"))
+
+       // URL method
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0")
+       assert.Equal(t, "g1/com.test.Service:1.0", u.ServiceKey())
+}
+
+func TestEncodedServiceKey(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&group=g1&version=1.0")
+       encoded := u.EncodedServiceKey()
+       assert.Equal(t, "g1*com.test.Service:1.0", encoded)
+}
+
+func TestServiceWithSubURL(t *testing.T) {
+       subURL, _ := NewURL("dubbo://127.0.0.1:20000?interface=com.sub.Service")
+       u := &URL{SubURL: subURL}
+       assert.Equal(t, "com.sub.Service", u.Service())
+
+       // empty SubURL interface
+       subURL2 := &URL{}
+       u2 := &URL{SubURL: subURL2, Path: "/com.path.Service"}
+       assert.Equal(t, "com.path.Service", u2.Service())
+
+       // no SubURL, no interface param
+       u3 := &URL{Path: "/com.path.Service"}
+       assert.Equal(t, "com.path.Service", u3.Service())
+}
+
+func TestAddParam(t *testing.T) {
+       u := &URL{}
+       u.AddParam("key1", "value1")
+       assert.Equal(t, "value1", u.GetParam("key1", ""))
+
+       // add another value to same key
+       u.AddParam("key1", "value2")
+       params := u.GetParams()
+       assert.Equal(t, 2, len(params["key1"]))
+}
+
+func TestAddParamAvoidNil(t *testing.T) {
+       u := &URL{}
+       u.AddParamAvoidNil("key1", "value1")
+       assert.Equal(t, "value1", u.GetParam("key1", ""))
+}
+
+func TestDelParam(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1&key2=value2")
+       u.DelParam("key1")
+       assert.Equal(t, "", u.GetParam("key1", ""))
+       assert.Equal(t, "value2", u.GetParam("key2", ""))
+
+       // delete from nil params
+       u2 := &URL{}
+       u2.DelParam("key") // should not panic
+}
+
+func TestGetNonDefaultParam(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1")
+
+       v, ok := u.GetNonDefaultParam("key1")
+       assert.True(t, ok)
+       assert.Equal(t, "value1", v)
+
+       v, ok = u.GetNonDefaultParam("nonexistent")
+       assert.False(t, ok)
+       assert.Equal(t, "", v)
+}
+
+func TestRangeParams(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1&key2=value2")
+       count := 0
+       u.RangeParams(func(key, value string) bool {
+               count++
+               return true
+       })
+       assert.Equal(t, 2, count)
+
+       // test early break
+       count = 0
+       u.RangeParams(func(key, value string) bool {
+               count++
+               return false // break after first
+       })
+       assert.Equal(t, 1, count)
+}
+
+func TestGetParamInt32(t *testing.T) {
+       params := url.Values{}
+       params.Set("key", "123")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       v := u.GetParamInt32("key", 0)
+       assert.Equal(t, int32(123), v)
+
+       // invalid value
+       u2 := &URL{}
+       v2 := u2.GetParamInt32("key", 99)
+       assert.Equal(t, int32(99), v2)
+}
+
+func TestGetParamByIntValue(t *testing.T) {
+       params := url.Values{}
+       params.Set("key", "456")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       v := u.GetParamByIntValue("key", 0)
+       assert.Equal(t, 456, v)
+
+       // invalid value
+       u2 := &URL{}
+       v2 := u2.GetParamByIntValue("key", 99)
+       assert.Equal(t, 99, v2)
+}
+
+func TestGetMethodParamIntValue(t *testing.T) {
+       params := url.Values{}
+       params.Set("methods.GetValue.timeout", "100")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       v := u.GetMethodParamIntValue("GetValue", "timeout", 0)
+       assert.Equal(t, 100, v)
+
+       // missing method param
+       v2 := u.GetMethodParamIntValue("OtherMethod", "timeout", 50)
+       assert.Equal(t, 50, v2)
+}
+
+func TestGetMethodParamInt64(t *testing.T) {
+       params := url.Values{}
+       params.Set("methods.GetValue.timeout", "200")
+       params.Set("timeout", "100")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       // method param exists
+       v := u.GetMethodParamInt64("GetValue", "timeout", 0)
+       assert.Equal(t, int64(200), v)
+
+       // method param not exists, fallback to global
+       v2 := u.GetMethodParamInt64("OtherMethod", "timeout", 0)
+       assert.Equal(t, int64(100), v2)
+
+       // neither exists
+       v3 := u.GetMethodParamInt64("OtherMethod", "retries", 5)
+       assert.Equal(t, int64(5), v3)
+}
+
+func TestGetParamDuration(t *testing.T) {
+       params := url.Values{}
+       params.Set("timeout", "5s")
+
+       u := &URL{}
+       u.SetParams(params)
+
+       d := u.GetParamDuration("timeout", "1s")
+       assert.Equal(t, 5*time.Second, d)
+
+       // invalid duration, returns 3s default
+       params2 := url.Values{}
+       params2.Set("timeout", "invalid")
+       u2 := &URL{}
+       u2.SetParams(params2)
+       d2 := u2.GetParamDuration("timeout", "invalid")
+       assert.Equal(t, 3*time.Second, d2)
+
+       // missing param with valid default
+       u3 := &URL{}
+       d3 := u3.GetParamDuration("timeout", "2s")
+       assert.Equal(t, 2*time.Second, d3)
+}
+
+func TestCloneExceptParams(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2&key3=value3")
+
+       excludeSet := gxset.NewSet("key1", "key3")
+       cloned := u.CloneExceptParams(excludeSet)
+
+       assert.Equal(t, "", cloned.GetParam("key1", ""))
+       assert.Equal(t, "value2", cloned.GetParam("key2", ""))
+       assert.Equal(t, "", cloned.GetParam("key3", ""))
+       assert.Equal(t, "dubbo", cloned.Protocol)
+}
+
+func TestCloneWithParams(t *testing.T) {
+       u, _ := 
NewURL("dubbo://user:[email protected]:20000/com.test.Service?key1=value1&key2=value2&key3=value3")
+       u.Methods = []string{"method1", "method2"}
+
+       cloned := u.CloneWithParams([]string{"key1", "key3"})
+
+       assert.Equal(t, "value1", cloned.GetParam("key1", ""))
+       assert.Equal(t, "", cloned.GetParam("key2", ""))
+       assert.Equal(t, "value3", cloned.GetParam("key3", ""))
+       assert.Equal(t, "dubbo", cloned.Protocol)
+       assert.Equal(t, "user", cloned.Username)
+       assert.Equal(t, "pass", cloned.Password)
+       assert.Equal(t, []string{"method1", "method2"}, cloned.Methods)
+}
+
+func TestURLCompare(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000/a.Service")
+       u2, _ := NewURL("dubbo://127.0.0.1:20000/b.Service")
+       u3, _ := NewURL("dubbo://127.0.0.1:20000/a.Service")
+
+       assert.Equal(t, -1, u1.Compare(u2))
+       assert.Equal(t, 1, u2.Compare(u1))
+       assert.Equal(t, 0, u1.Compare(u3))
+}
+
+func TestRangeAttributes(t *testing.T) {
+       u := &URL{}
+       u.SetAttribute("attr1", "value1")
+       u.SetAttribute("attr2", 123)
+
+       count := 0
+       u.RangeAttributes(func(key string, value any) bool {
+               count++
+               return true
+       })
+       assert.Equal(t, 2, count)
+
+       // test early break
+       count = 0
+       u.RangeAttributes(func(key string, value any) bool {
+               count++
+               return false
+       })
+       assert.Equal(t, 1, count)
+}
+
+func TestURLSlice(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000/c.Service")
+       u2, _ := NewURL("dubbo://127.0.0.1:20000/a.Service")
+       u3, _ := NewURL("dubbo://127.0.0.1:20000/b.Service")
+
+       slice := URLSlice{u1, u2, u3}
+
+       assert.Equal(t, 3, slice.Len())
+       assert.True(t, slice.Less(1, 2))  // a < b
+       assert.False(t, slice.Less(0, 2)) // c > b
+
+       slice.Swap(0, 1)
+       assert.Equal(t, u2, slice[0])
+       assert.Equal(t, u1, slice[1])
+}
+
+func TestIsEquals(t *testing.T) {
+       u1, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2")
+       u2, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=value2")
+       u3, _ := 
NewURL("dubbo://127.0.0.1:20001/com.test.Service?key1=value1&key2=value2")
+       u4, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key1=value1&key2=different")
+
+       // equal URLs
+       assert.True(t, IsEquals(u1, u2))
+
+       // different port
+       assert.False(t, IsEquals(u1, u3))
+
+       // different param value
+       assert.False(t, IsEquals(u1, u4))
+
+       // with excludes
+       assert.True(t, IsEquals(u1, u4, "key2"))
+
+       // nil checks
+       assert.False(t, IsEquals(nil, u1))
+       assert.False(t, IsEquals(u1, nil))
+}
+
+func TestGetSubscribeName(t *testing.T) {
+       u, _ := 
NewURL("dubbo://127.0.0.1:20000?interface=com.test.Service&version=1.0&group=test")
+       name := GetSubscribeName(u)
+       assert.Contains(t, name, "providers")
+       assert.Contains(t, name, "com.test.Service")
+       assert.Contains(t, name, "1.0")
+       assert.Contains(t, name, "test")
+}
+
+func TestNewURLEmptyString(t *testing.T) {
+       u, err := NewURL("")
+       assert.NoError(t, err)
+       assert.NotNil(t, u)
+       assert.Equal(t, "", u.Protocol)
+}
+
+func TestNewURLWithUsernamePassword(t *testing.T) {
+       u, err := 
NewURL("dubbo://admin:[email protected]:20000/com.test.Service")
+       assert.NoError(t, err)
+       assert.Equal(t, "admin", u.Username)
+       assert.Equal(t, "secret", u.Password)
+}
+
+func TestURLStringWithCredentials(t *testing.T) {
+       u, _ := 
NewURL("dubbo://admin:[email protected]:20000/com.test.Service?key=value")
+       str := u.String()
+       assert.Contains(t, str, "admin:secret@")
+}
+
+func TestToMapWithoutPort(t *testing.T) {
+       u := &URL{
+               Protocol: "dubbo",
+               Location: "127.0.0.1",
+               Path:     "/com.test.Service",
+       }
+       m := u.ToMap()
+       assert.Equal(t, "0", m["port"])
+}
+
+func TestToMapEmpty(t *testing.T) {
+       u := &URL{}
+       m := u.ToMap()
+       assert.Nil(t, m)
+}
+
+func TestMergeURLWithAttributes(t *testing.T) {
+       u1, _ := NewURL("dubbo://127.0.0.1:20000?key1=value1")
+       u1.SetAttribute("attr1", "attrValue1")
+
+       u2, _ := NewURL("dubbo://127.0.0.1:20001?key2=value2")
+       u2.SetAttribute("attr2", "attrValue2")
+       u2.Methods = []string{"method1"}
+
+       merged := u1.MergeURL(u2)
+
+       // attributes should be merged
+       v1, ok1 := merged.GetAttribute("attr1")
+       assert.True(t, ok1)
+       assert.Equal(t, "attrValue1", v1)
+
+       v2, ok2 := merged.GetAttribute("attr2")
+       assert.True(t, ok2)
+       assert.Equal(t, "attrValue2", v2)
+}
+
+func TestURLEqualWithCategory(t *testing.T) {
+       // test category matching with RemoveValuePrefix
+       u1, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&category=providers")
+       u2, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&category=-providers")
+       assert.False(t, u1.URLEqual(u2))
+
+       // category contains target - u3 has category that contains u1's 
category
+       u3, _ := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?interface=com.test.Service&category=providers,consumers")
+       // u1 checks if u3's category matches - u3 has "providers,consumers" 
which contains "providers"
+       assert.True(t, u3.URLEqual(u1))
+}
+
+func TestNewURLWithRegistryGroup(t *testing.T) {
+       u, err := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?registry.group=mygroup")
+       assert.NoError(t, err)
+       assert.Contains(t, u.PrimitiveURL, "mygroup")
+}
+
+func TestColonSeparatedKeyEmpty(t *testing.T) {
+       u := &URL{}
+       assert.Equal(t, "", u.ColonSeparatedKey())
+}
+
+func TestColonSeparatedKeyWithVersion000(t *testing.T) {
+       u, _ := NewURL("dubbo://127.0.0.1:20000")
+       u.AddParam(constant.InterfaceKey, "com.test.Service")
+       u.AddParam(constant.VersionKey, "0.0.0")
+       u.AddParam(constant.GroupKey, "group1")
+
+       // version 0.0.0 should be treated as empty
+       assert.Equal(t, "com.test.Service::group1", u.ColonSeparatedKey())
+}
+
+// Additional edge case tests for better coverage
+
+func TestNewURLParseError(t *testing.T) {
+       // Test invalid URL that causes parse error
+       _, err := NewURL("://invalid")
+       assert.Error(t, err)
+}
+
+func TestNewURLWithInvalidQuery(t *testing.T) {
+       // URL with special characters that need escaping
+       u, err := 
NewURL("dubbo://127.0.0.1:20000/com.test.Service?key=value%20with%20space")
+       assert.NoError(t, err)
+       assert.Equal(t, "value with space", u.GetParam("key", ""))
+}

Review Comment:
   The test name and comment indicate this tests "invalid query" handling, but 
the URL used contains valid percent-encoded characters that should decode 
successfully. This is not actually testing an invalid query scenario. Consider 
renaming to "TestNewURLWithEncodedQuery" or similar to accurately reflect what 
is being tested.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to