package domain import ( "encoding/json" "github.com/stretchr/testify/assert" "testing" "time" ) // assertJSONEqual сравнивает JSON, игнорируя пробелы и порядок ключей func assertJSONEqual(t *testing.T, expected string, actual []byte) { var expectedMap, actualMap map[string]any if err := json.Unmarshal([]byte(expected), &expectedMap); err != nil { t.Fatalf("Ошибка десериализации ожидаемого JSON: %v", err) } if err := json.Unmarshal(actual, &actualMap); err != nil { t.Fatalf("Ошибка десериализации полученного JSON: %v", err) } if len(expectedMap) != len(actualMap) { t.Errorf("Разное количество ключей в JSON: ожидалось %d, получено %d", len(expectedMap), len(actualMap)) } for key, expectedValue := range expectedMap { actualValue, exists := actualMap[key] if !exists { t.Errorf("Ключ %q отсутствует в JSON", key) } else if actualValue != expectedValue { t.Errorf("Для ключа %q ожидалось %v, получено %v", key, expectedValue, actualValue) } } } func TestUserMarshalJSON(t *testing.T) { validDate := CustomDate{Time: time.Date(1990, time.July, 10, 0, 0, 0, 0, time.UTC)} regDate := CustomDate{Time: time.Date(2023, time.March, 15, 0, 0, 0, 0, time.UTC)} testTable := []struct { name string user User expected string }{ { name: "ok", user: User{ ID: 42, Username: "alice", Email: "alice@example.com", AvatarImage: "https://example.com/avatar.png", BlackPhoenix: true, DateOfBirth: validDate, DateOfRegistration: regDate, }, expected: `{ "id": 42, "username": "alice", "email": "alice@example.com", "avatar_image": "https://example.com/avatar.png", "black_phoenix": true, "date_of_birth": "1990-07-10", "date_of_registration": "2023-03-15" }`, }, { name: "zero_values", user: User{}, expected: `{ "id": 0, "username": "", "email": "", "avatar_image": "", "black_phoenix": false, "date_of_birth": "0001-01-01", "date_of_registration": "0001-01-01" }`, }, { name: "special_characters", user: User{ ID: 1, Username: `test"user`, Email: "test@example.com\nnewline", AvatarImage: `https://example.com/avatar.png`, }, expected: `{ "id": 1, "username": "test\"user", "email": "test@example.com\nnewline", "avatar_image": "https://example.com/avatar.png", "black_phoenix": false, "date_of_birth": "0001-01-01", "date_of_registration": "0001-01-01" }`, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { result, err := json.Marshal(tc.user) if err != nil { t.Fatalf("Ошибка сериализации: %v", err) } assertJSONEqual(t, tc.expected, result) }) } } func TestCustomDate_UnmarshalJSON(t *testing.T) { testTable := []struct { name string input string expectErr bool expected time.Time }{ { name: "ok", input: `"2024-02-25"`, expected: time.Date(2024, 2, 25, 0, 0, 0, 0, time.UTC), }, { name: "invalid_format", input: `"25-02-2024"`, expectErr: true, }, { name: "invalid_characters", input: `"invalid-date"`, expectErr: true, }, { name: "empty_string", input: `""`, expectErr: true, }, { name: "whitespace", input: `" "`, expectErr: true, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { var cd CustomDate err := json.Unmarshal([]byte(tc.input), &cd) assert.Equal(t, tc.expectErr, err != nil) assert.True(t, cd.Time.Equal(tc.expected) || tc.expectErr) }) } } func TestCustomDate_MarshalJSON(t *testing.T) { testTable := []struct { name string date CustomDate expected string }{ { name: "ok_1", date: CustomDate{Time: time.Date(2024, 2, 25, 0, 0, 0, 0, time.UTC)}, expected: `"2024-02-25"`, }, { name: "ok_2", date: CustomDate{Time: time.Date(2023, 8, 10, 0, 0, 0, 0, time.UTC)}, expected: `"2023-08-10"`, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { result, err := json.Marshal(tc.date) assert.NoError(t, err) assert.Equal(t, tc.expected, string(result)) }) } } func TestCustomDate_String(t *testing.T) { testTable := []struct { name string date CustomDate expected string }{ { name: "ok_1", date: CustomDate{Time: time.Date(2024, 2, 25, 0, 0, 0, 0, time.UTC)}, expected: "2024-02-25", }, { name: "ok_2", date: CustomDate{Time: time.Date(2023, 8, 10, 0, 0, 0, 0, time.UTC)}, expected: "2023-08-10", }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { result := tc.date.String() assert.Equal(t, tc.expected, result) }) } } func TestCustomDate_Scan(t *testing.T) { testTable := []struct { name string dbValue any expected CustomDate expectedErr error panics bool }{ { name: "ok_1", dbValue: "2023-08-10", expected: CustomDate{Time: time.Date(2023, 8, 10, 0, 0, 0, 0, time.UTC)}, }, { name: "ok_2", dbValue: time.Date(2023, 8, 10, 0, 0, 0, 0, time.UTC), expected: CustomDate{Time: time.Date(2023, 8, 10, 0, 0, 0, 0, time.UTC)}, }, { name: "invalid_date", dbValue: "", expectedErr: &time.ParseError{}, }, { name: "invalid_type", panics: true, }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { if tc.panics { defer func() { if r := recover(); r != nil { assert.Equal(t, "incorrect time type received", r) } }() } date := &CustomDate{} err := date.Scan(tc.dbValue) if tc.expectedErr != nil { assert.ErrorAs(t, err, &tc.expectedErr) } else { assert.NoError(t, err) } assert.Equal(t, tc.expected, *date) }) } } func TestCustomDate_Value(t *testing.T) { testTable := []struct { name string date CustomDate expected string }{ { name: "ok_1", date: CustomDate{Time: time.Date(2024, 2, 25, 0, 0, 0, 0, time.UTC)}, expected: "2024-02-25", }, { name: "ok_2", date: CustomDate{Time: time.Date(2023, 8, 10, 0, 0, 0, 0, time.UTC)}, expected: "2023-08-10", }, } for _, tc := range testTable { t.Run(tc.name, func(t *testing.T) { result, err := tc.date.Value() assert.NoError(t, err) date, ok := result.(string) assert.True(t, ok) assert.Equal(t, tc.expected, date) }) } }