package exception import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestContextWithServiceAndEndpoint(t *testing.T) { ctx := context.Background() ctx = ContextWithService(ctx, "my_service") ctx = ContextWithEndpoint(ctx, "my_endpoint") svc := extractFromCtx(ctx, ctxKeyService, "fallback") ep := extractFromCtx(ctx, ctxKeyEndpoint, "fallback") assert.Equal(t, "my_service", svc) assert.Equal(t, "my_endpoint", ep) } func TestExtractFromCtxFallback(t *testing.T) { ctx := context.Background() val := extractFromCtx(ctx, ctxKeyService, "default") assert.Equal(t, "default", val) } func TestBuilderString(t *testing.T) { // Use proper 3-char endpoint and service to form a 13-char code ctx := ContextWithService(context.Background(), ServiceAuthToken) ctx = ContextWithEndpoint(ctx, EndpointAuthToken) b := New( WithStatus(StatusSuccess), WithType(TypeCommon), WithOriginal(CommonSuccess), ).Throw(ctx) s := b.String() require.Len(t, s, 13, "error code must be 13 chars") assert.Equal(t, StatusSuccess, string(s[0])) } func TestBuilderThrowSuccess(t *testing.T) { ctx := ContextWithService(context.Background(), ServiceAuthToken) ctx = ContextWithEndpoint(ctx, EndpointAuthToken) b := New( WithStatus(StatusSuccess), WithType(TypeCommon), WithOriginal(CommonSuccess), ).Throw(ctx) assert.Equal(t, CommonSuccess, b.Original) assert.NotEmpty(t, b.ErrorCode) } func TestBuilderThrowWithError(t *testing.T) { ctx := ContextWithService(context.Background(), ServiceAuthToken) ctx = ContextWithEndpoint(ctx, EndpointAuthToken) origErr := errors.New("something went wrong") b := New( WithStatus(StatusUser), WithType(TypeSpecific), WithOriginal(CommonErrorUnauthorized), WithError(origErr), ).Throw(ctx) assert.Equal(t, origErr, b.Error) assert.Equal(t, StatusUser, b.Status) } func TestBuilderWithOptionsApplied(t *testing.T) { err := errors.New("test") b := New( WithStatus(StatusServer), WithType(TypeSpecific), WithOriginal(CommonErrorInternal), WithError(err), ) assert.Equal(t, StatusServer, b.Status) assert.Equal(t, TypeSpecific, b.Type) assert.Equal(t, CommonErrorInternal, b.Original) assert.Equal(t, err, b.Error) } func TestBuilderErrorCodeLength(t *testing.T) { ctx := ContextWithService(context.Background(), "svc") ctx = ContextWithEndpoint(ctx, "ep_") b := New( WithStatus(StatusSuccess), WithType(TypeCommon), WithOriginal(CommonSuccess), ).Throw(ctx) // Status(1) + Endpoint(3) + Service(3) + Type(1) + Original(5) = 13 assert.Len(t, b.ErrorCode, 13) } func TestErrorHandlerDoesNotPanic(t *testing.T) { ctx := context.Background() testErr := errors.New("test error") for _, status := range []string{StatusSuccess, StatusUser, StatusServer, StatusClient} { s := status assert.NotPanics(t, func() { ErrorHandler(ctx, s, "code12345678", testErr) }, "ErrorHandler must not panic for status %q", s) } } func TestErrorHandlerNilError(t *testing.T) { ctx := context.Background() assert.NotPanics(t, func() { ErrorHandler(ctx, StatusUser, "code12345678", nil) }) } func TestBuilderNilThrow(t *testing.T) { b := New( WithStatus(StatusSuccess), WithType(TypeCommon), WithOriginal(CommonSuccess), ) // Throw on empty context (no service/endpoint set) must not panic assert.NotPanics(t, func() { thrown := b.Throw(context.Background()) assert.Equal(t, CommonSuccess, thrown.Original) }) }