From b1df9e4f3a77a0611bfc7fe1c74ecad78a97c625 Mon Sep 17 00:00:00 2001 From: hmmftg Date: Mon, 27 Oct 2025 09:52:05 +0330 Subject: [PATCH] feat: add comprehensive tests for NewWithDescription error creation - Introduced multiple test cases for the NewWithDescription function to validate error messages with various formats and arguments. - Enhanced error logging structure in ErrorData to group error attributes for better clarity. - Updated error logging in response package to maintain consistency with the new structure. --- libError/error_test.go | 149 +++++++++++++++++++++++++++++++++++++++++ libError/errordata.go | 12 ++-- response/errorData.go | 12 ++-- 3 files changed, 163 insertions(+), 10 deletions(-) diff --git a/libError/error_test.go b/libError/error_test.go index 8915743..607feea 100644 --- a/libError/error_test.go +++ b/libError/error_test.go @@ -127,3 +127,152 @@ func TestErrorSlogText(t *testing.T) { } } } + +func TestNewWithDescription(t *testing.T) { + tests := []struct { + name string + status status.StatusCode + desc string + format string + args []interface{} + expectedMsg string + }{ + { + name: "Simple string without format", + status: status.BadRequest, + desc: "VALIDATION_ERROR", + format: "User not found", + args: nil, + expectedMsg: "User not found", + }, + { + name: "String with single argument", + status: status.NotFound, + desc: "USER_NOT_FOUND", + format: "User with ID %d not found", + args: []interface{}{123}, + expectedMsg: "User with ID 123 not found", + }, + { + name: "String with multiple arguments", + status: status.BadRequest, + desc: "INVALID_INPUT", + format: "Invalid input: %s, value: %d", + args: []interface{}{"age", 150}, + expectedMsg: "Invalid input: age, value: 150", + }, + { + name: "String with string argument", + status: status.InternalServerError, + desc: "DATABASE_ERROR", + format: "Database error: %s", + args: []interface{}{"connection timeout"}, + expectedMsg: "Database error: connection timeout", + }, + { + name: "String with float argument", + status: status.BadRequest, + desc: "INVALID_VALUE", + format: "Value %.2f is out of range", + args: []interface{}{3.14159}, + expectedMsg: "Value 3.14 is out of range", + }, + { + name: "String with bool argument", + status: status.BadRequest, + desc: "INVALID_FLAG", + format: "Feature enabled: %t", + args: []interface{}{true}, + expectedMsg: "Feature enabled: true", + }, + { + name: "String with multiple types", + status: status.BadRequest, + desc: "VALIDATION_FAILED", + format: "User %s (ID: %d, Age: %d) - Status: %t", + args: []interface{}{"John Doe", 1001, 25, true}, + expectedMsg: "User John Doe (ID: 1001, Age: 25) - Status: true", + }, + { + name: "String with percent sign", + status: status.BadRequest, + desc: "PERCENTAGE_ERROR", + format: "Progress: %d%% completed", + args: []interface{}{75}, + expectedMsg: "Progress: 75% completed", + }, + { + name: "String with no placeholders but args provided", + status: status.BadRequest, + desc: "SIMPLE_ERROR", + format: "Simple error message", + args: []interface{}{"extra", 123}, + expectedMsg: "Simple error message", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := libError.NewWithDescription(tt.status, tt.desc, tt.format, tt.args...) + + // Check that error is not nil + if err == nil { + t.Fatal("Expected error to be not nil") + } + + // Get error string + errStr := err.Error() + + // Check if error string contains the expected message + if !strings.Contains(errStr, tt.expectedMsg) { + t.Errorf("Expected error message to contain '%s', but got '%s'", tt.expectedMsg, errStr) + } + + // Check that description is in the error + if !strings.Contains(errStr, tt.desc) { + t.Errorf("Expected error to contain description '%s', but got '%s'", tt.desc, errStr) + } + + // Check action data + action := err.Action() + if action.Status != tt.status { + t.Errorf("Expected status %d, but got %d", tt.status, action.Status) + } + + if action.Description != tt.desc { + t.Errorf("Expected description '%s', but got '%s'", tt.desc, action.Description) + } + + // Check the message in action data + msgStr := fmt.Sprintf("%v", action.Message) + if !strings.Contains(msgStr, tt.expectedMsg) { + t.Errorf("Expected action message to contain '%s', but got '%s'", tt.expectedMsg, msgStr) + } + + // Check that source is set + if err.Src() == nil { + t.Error("Expected source to be set, but got nil") + } + }) + } +} + +func TestNewWithDescription_EmptyFormat(t *testing.T) { + err := libError.NewWithDescription(status.BadRequest, "TEST", "") + + if err == nil { + t.Fatal("Expected error to be not nil") + } + + errStr := err.Error() + + // Should still be a valid error + if errStr == "" { + t.Error("Expected non-empty error string") + } + + // Check description is present + if !strings.Contains(errStr, "TEST") { + t.Errorf("Expected error to contain 'TEST', but got '%s'", errStr) + } +} diff --git a/libError/errordata.go b/libError/errordata.go index 74c09e6..ae94377 100644 --- a/libError/errordata.go +++ b/libError/errordata.go @@ -36,10 +36,12 @@ func (e ErrorData) LogValue() slog.Value { src = slog.Attr{} } return slog.GroupValue( - slog.Time("time", e.Time), - slog.String("desc", e.ActionData.Description), - slog.Any("action", e.ActionData), - src, - slog.Any("child", e.Child), + slog.Group("error", + slog.Time("time", e.Time), + slog.String("desc", e.ActionData.Description), + slog.Any("action", e.ActionData), + src, + slog.Any("child", e.Child), + ), ) } diff --git a/response/errorData.go b/response/errorData.go index e7db016..06f2822 100644 --- a/response/errorData.go +++ b/response/errorData.go @@ -33,11 +33,13 @@ func (e ErrorData) LogValue() slog.Value { children = append(children, slog.Any(e.childs[id].GetDescription(), e.childs[id])) } return slog.GroupValue( - slog.Int("status", e.Status), - slog.String("desc", e.Description), - slog.Any("message", e.Message), - slog.Any("source", e.source), - slog.Group("children", children...), + slog.Group("error", + slog.Int("status", e.Status), + slog.String("desc", e.Description), + slog.Any("message", e.Message), + slog.Any("source", e.source), + slog.Group("children", children...), + ), ) }