diff --git a/fxgrpcserver/reflect.go b/fxgrpcserver/reflect.go index cb7933b0..f53cf5c0 100644 --- a/fxgrpcserver/reflect.go +++ b/fxgrpcserver/reflect.go @@ -4,12 +4,39 @@ import ( "reflect" ) -// GetType returns the type of a target. +// fullTypeID builds a stable identifier for a type in the form ".". +func fullTypeID(t reflect.Type) string { + if t == nil { + return "" + } + + // Unwrap pointers to get the underlying named type (if any). + for t.Kind() == reflect.Pointer { + t = t.Elem() + } + + // For named types, PkgPath() + Name() gives a unique and stable identity. + if t.Name() != "" && t.PkgPath() != "" { + return t.PkgPath() + "." + t.Name() + } + + // Fallback for non-named kinds (slices, maps, func, etc.). + return t.String() +} + +// GetType returns a stable identifier for the given target’s type. func GetType(target any) string { - return reflect.TypeOf(target).String() + return fullTypeID(reflect.TypeOf(target)) } -// GetReturnType returns the return type of a target. +// GetReturnType returns a stable identifier for the return type of constructor-like target. +// If a target is a function, we examine its first return value (index 0), unwrap pointers, and +// build an identifier for that named type. For non-function or empty-return cases, we return "". func GetReturnType(target any) string { - return reflect.TypeOf(target).Out(0).String() + t := reflect.TypeOf(target) + if t == nil || t.Kind() != reflect.Func || t.NumOut() == 0 { + return "" + } + + return fullTypeID(t.Out(0)) } diff --git a/fxgrpcserver/reflect_test.go b/fxgrpcserver/reflect_test.go index f6199b3b..c9b70158 100644 --- a/fxgrpcserver/reflect_test.go +++ b/fxgrpcserver/reflect_test.go @@ -3,7 +3,7 @@ package fxgrpcserver_test import ( "testing" - "github.com/ankorstore/yokai/fxhealthcheck" + "github.com/ankorstore/yokai/fxgrpcserver" "github.com/ankorstore/yokai/fxhealthcheck/testdata/probes" "github.com/stretchr/testify/assert" ) @@ -15,10 +15,11 @@ func TestGetType(t *testing.T) { target any expected string }{ + {nil, ""}, {123, "int"}, {"test", "string"}, - {probes.NewSuccessProbe(), "*probes.SuccessProbe"}, - {probes.NewFailureProbe(), "*probes.FailureProbe"}, + {probes.NewSuccessProbe(), "github.com/ankorstore/yokai/fxhealthcheck/testdata/probes.SuccessProbe"}, + {probes.NewFailureProbe(), "github.com/ankorstore/yokai/fxhealthcheck/testdata/probes.FailureProbe"}, } for _, tt := range tests { @@ -27,7 +28,7 @@ func TestGetType(t *testing.T) { t.Run(tt.expected, func(t *testing.T) { t.Parallel() - got := fxhealthcheck.GetType(tt.target) + got := fxgrpcserver.GetType(tt.target) assert.Equal(t, tt.expected, got) }) } @@ -40,6 +41,7 @@ func TestGetReturnType(t *testing.T) { target any expected string }{ + {nil, ""}, {func() string { return "test" }, "string"}, {func() int { return 123 }, "int"}, } @@ -49,7 +51,7 @@ func TestGetReturnType(t *testing.T) { t.Run(tt.expected, func(t *testing.T) { t.Parallel() - got := fxhealthcheck.GetReturnType(tt.target) + got := fxgrpcserver.GetReturnType(tt.target) assert.Equal(t, tt.expected, got) }) }