From 7f9a1f5a9830bd44e3ec700d89a09d7b55af8b14 Mon Sep 17 00:00:00 2001 From: Jamie Curnow Date: Thu, 27 Jul 2023 21:17:08 +1000 Subject: [PATCH] Add more backend unit tests --- backend/internal/tags/filters_test.go | 156 ++++++++++++++++++ backend/internal/types/db_date_test.go | 110 ++++++++++++ .../internal/types/db_nullable_int_test.go | 91 ++++++++++ .../internal/types/db_nullable_uint_test.go | 146 ++++++++++++++++ backend/internal/types/jsonb_test.go | 133 +++++++++++++++ .../internal/types/nullable_db_date_test.go | 107 ++++++++++++ backend/internal/util/interfaces_test.go | 33 ++++ backend/internal/util/slices_test.go | 19 +++ backend/internal/util/strings_test.go | 16 ++ backend/internal/util/time_test.go | 25 +++ 10 files changed, 836 insertions(+) create mode 100644 backend/internal/tags/filters_test.go create mode 100644 backend/internal/types/db_date_test.go create mode 100644 backend/internal/types/db_nullable_int_test.go create mode 100644 backend/internal/types/db_nullable_uint_test.go create mode 100644 backend/internal/types/jsonb_test.go create mode 100644 backend/internal/types/nullable_db_date_test.go create mode 100644 backend/internal/util/interfaces_test.go create mode 100644 backend/internal/util/time_test.go diff --git a/backend/internal/tags/filters_test.go b/backend/internal/tags/filters_test.go new file mode 100644 index 0000000..671ecd8 --- /dev/null +++ b/backend/internal/tags/filters_test.go @@ -0,0 +1,156 @@ +package tags + +import ( + "npm/internal/util" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetFilterSchema(t *testing.T) { + m := struct { + ID int `filter:"id"` + Name string `filter:"name"` + }{ + ID: 1, + Name: "John", + } + + filterSchema := util.PrettyPrintJSON(GetFilterSchema(m)) + + expectedSchema := `{ + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "field": { + "type": "string", + "pattern": "^id$" + }, + "modifier": { + "type": "string", + "pattern": "^(equals|not|contains|starts|ends|in|notin)$" + }, + "value": { + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + ] + } + } + }, + { + "type": "object", + "properties": { + "field": { + "type": "string", + "pattern": "^name$" + }, + "modifier": { + "type": "string", + "pattern": "^(equals|not|contains|starts|ends|in|notin)$" + }, + "value": { + "oneOf": [ + { + "type": "string", + "minLength": 1 + }, + { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + } + } + ] + } + } + } + ] + } +}` + + assert.Equal(t, expectedSchema, filterSchema) +} + +func TestGetFilterTagSchema(t *testing.T) { + schema := util.PrettyPrintJSON(getFilterTagSchema("id,integer")) + + expectedSchema := `{ + "type": "object", + "properties": { + "field": { + "type": "string", + "pattern": "^id$" + }, + "modifier": { + "type": "string", + "pattern": "^(equals|not|contains|starts|ends|in|notin|min|max|greater|less)$" + }, + "value": { + "oneOf": [ + { + "type": "string", + "pattern": "^[0-9]+$" + }, + { + "type": "array", + "items": { + "type": "string", + "pattern": "^[0-9]+$" + } + } + ] + } + } +}` + + assert.Equal(t, expectedSchema, schema) +} + +func TestBoolFieldSchema(t *testing.T) { + schema := util.PrettyPrintJSON(boolFieldSchema("active")) + + expectedSchema := `{ + "type": "object", + "properties": { + "field": { + "type": "string", + "pattern": "^active$" + }, + "modifier": { + "type": "string", + "pattern": "^(equals|not)$" + }, + "value": { + "oneOf": [ + { + "type": "string", + "pattern": "^(TRUE|true|t|yes|y|on|1|FALSE|f|false|n|no|off|0)$" + }, + { + "type": "array", + "items": { + "type": "string", + "pattern": "^(TRUE|true|t|yes|y|on|1|FALSE|f|false|n|no|off|0)$" + } + } + ] + } + } +}` + + assert.Equal(t, expectedSchema, schema) +} diff --git a/backend/internal/types/db_date_test.go b/backend/internal/types/db_date_test.go new file mode 100644 index 0000000..c9ca494 --- /dev/null +++ b/backend/internal/types/db_date_test.go @@ -0,0 +1,110 @@ +package types + +import ( + "encoding/json" + "testing" + "time" +) + +func TestDBDate_Value(t *testing.T) { + // Create a DBDate instance with a specific time + expectedTime := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + dbDate := DBDate{Time: expectedTime} + + // Call the Value method + value, err := dbDate.Value() + + // Assert the value and error + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // Convert the value to int64 + unixTime := value.(int64) + + // Convert the unix time back to time.Time + actualTime := time.Unix(unixTime, 0) + + // Compare the actual time with the expected time + if !actualTime.Equal(expectedTime) { + t.Errorf("Expected time '%v', got '%v'", expectedTime, actualTime) + } +} + +func TestDBDate_Scan(t *testing.T) { + // Simulate a value from the database (unix timestamp) + unixTime := int64(1640995200) + + // Create a DBDate instance + dbDate := DBDate{} + + // Call the Scan method + err := dbDate.Scan(unixTime) + + // Assert the error + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // Convert the DBDate's time to unix timestamp for comparison + actualUnixTime := dbDate.Time.Unix() + + // Compare the actual unix time with the expected unix time + if actualUnixTime != unixTime { + t.Errorf("Expected unix time '%v', got '%v'", unixTime, actualUnixTime) + } +} + +func TestDBDate_UnmarshalJSON(t *testing.T) { + // Simulate a JSON input representing a unix timestamp + jsonData := []byte("1640995200") + + // Create a DBDate instance + dbDate := DBDate{} + + // Call the UnmarshalJSON method + err := dbDate.UnmarshalJSON(jsonData) + + // Assert the error + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // Convert the DBDate's time to unix timestamp for comparison + actualUnixTime := dbDate.Time.Unix() + + // Compare the actual unix time with the expected unix time + expectedUnixTime := int64(1640995200) + if actualUnixTime != expectedUnixTime { + t.Errorf("Expected unix time '%v', got '%v'", expectedUnixTime, actualUnixTime) + } +} + +func TestDBDate_MarshalJSON(t *testing.T) { + // Create a DBDate instance with a specific time + expectedTime := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + dbDate := DBDate{Time: expectedTime} + + // Call the MarshalJSON method + jsonData, err := dbDate.MarshalJSON() + + // Assert the value and error + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // Convert the JSON data to an integer + var actualUnixTime int64 + err = json.Unmarshal(jsonData, &actualUnixTime) + if err != nil { + t.Errorf("Failed to unmarshal JSON data: %v", err) + } + + // Convert the unix time back to time.Time + actualTime := time.Unix(actualUnixTime, 0) + + // Compare the actual time with the expected time + if !actualTime.Equal(expectedTime) { + t.Errorf("Expected time '%v', got '%v'", expectedTime, actualTime) + } +} diff --git a/backend/internal/types/db_nullable_int_test.go b/backend/internal/types/db_nullable_int_test.go new file mode 100644 index 0000000..4791404 --- /dev/null +++ b/backend/internal/types/db_nullable_int_test.go @@ -0,0 +1,91 @@ +package types + +import ( + "testing" +) + +func TestNullableDBIntValue(t *testing.T) { + var d NullableDBInt + + // Test when Int is 0 (null) + d.Int = 0 + value, err := d.Value() + if value != nil || err != nil { + t.Errorf("Expected Value() to return nil, nil but got %v, %v", value, err) + } + + // Test when Int is not null + d.Int = 10 + value, err = d.Value() + if value != int64(10) || err != nil { + t.Errorf("Expected Value() to return 10, nil but got %v, %v", value, err) + } +} + +func TestNullableDBIntScan(t *testing.T) { + var d NullableDBInt + + // Test when src is an int + err := d.Scan(20) + if d.Int != 20 || err != nil { + t.Errorf("Expected Scan(20) to set d.Int to 20 and return nil but got d.Int = %d, err = %v", d.Int, err) + } + + // Test when src is an int64 + err = d.Scan(int64(30)) + if d.Int != 30 || err != nil { + t.Errorf("Expected Scan(int64(30)) to set d.Int to 30 and return nil but got d.Int = %d, err = %v", d.Int, err) + } + + // Test when src is a float32 + err = d.Scan(float32(40)) + if d.Int != 40 || err != nil { + t.Errorf("Expected Scan(float32(40)) to set d.Int to 40 and return nil but got d.Int = %d, err = %v", d.Int, err) + } + + // Test when src is a float64 + err = d.Scan(float64(50)) + if d.Int != 50 || err != nil { + t.Errorf("Expected Scan(float64(50)) to set d.Int to 50 and return nil but got d.Int = %d, err = %v", d.Int, err) + } + + // Test when src is a string + err = d.Scan("60") + if d.Int != 60 || err != nil { + t.Errorf("Expected Scan(\"60\") to set d.Int to 60 and return nil but got d.Int = %d, err = %v", d.Int, err) + } +} + +func TestNullableDBIntUnmarshalJSON(t *testing.T) { + var d NullableDBInt + + // Test when data is an integer value + err := d.UnmarshalJSON([]byte("10")) + if d.Int != 10 || err != nil { + t.Errorf("Expected UnmarshalJSON([]byte(\"10\")) to set d.Int to 10 and return nil but got d.Int = %d, err = %v", d.Int, err) + } + + // Test when data is null + err = d.UnmarshalJSON([]byte("null")) + if d.Int != 0 || err != nil { + t.Errorf("Expected UnmarshalJSON([]byte(\"null\")) to set d.Int to 0 and return nil but got d.Int = %d, err = %v", d.Int, err) + } +} + +func TestNullableDBIntMarshalJSON(t *testing.T) { + var d NullableDBInt + + // Test when Int is 0 (null) + d.Int = 0 + result, err := d.MarshalJSON() + if string(result) != "null" || err != nil { + t.Errorf("Expected MarshalJSON() to return \"null\", nil but got %s, %v", result, err) + } + + // Test when Int is not null + d.Int = 10 + result, err = d.MarshalJSON() + if string(result) != "10" || err != nil { + t.Errorf("Expected MarshalJSON() to return \"10\", nil but got %s, %v", result, err) + } +} diff --git a/backend/internal/types/db_nullable_uint_test.go b/backend/internal/types/db_nullable_uint_test.go new file mode 100644 index 0000000..8c87b7c --- /dev/null +++ b/backend/internal/types/db_nullable_uint_test.go @@ -0,0 +1,146 @@ +package types + +import ( + "database/sql/driver" + "testing" +) + +func TestNullableDBUint_Value(t *testing.T) { + tests := []struct { + name string + input NullableDBUint + wantValue driver.Value + wantErr bool + }{ + { + name: "Value should return nil when Uint is 0", + input: NullableDBUint{Uint: 0}, + wantValue: nil, + wantErr: false, + }, + { + name: "Value should return int64 value of Uint", + input: NullableDBUint{Uint: 10}, + wantValue: int64(10), + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotValue, gotErr := tt.input.Value() + if gotValue != tt.wantValue { + t.Errorf("Value() = %v, want %v", gotValue, tt.wantValue) + } + if (gotErr != nil) != tt.wantErr { + t.Errorf("Value() error = %v, wantErr %v", gotErr, tt.wantErr) + } + }) + } +} + +func TestNullableDBUint_Scan(t *testing.T) { + tests := []struct { + name string + input interface{} + wantUint uint + wantErr bool + }{ + { + name: "Scan should convert int to uint", + input: int(10), + wantUint: uint(10), + wantErr: false, + }, + { + name: "Scan should convert int64 to uint", + input: int64(10), + wantUint: uint(10), + wantErr: false, + }, + // Add more tests for other supported types + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var d NullableDBUint + err := d.Scan(tt.input) + if err != nil && !tt.wantErr { + t.Errorf("Scan() error = %v, wantErr %v", err, tt.wantErr) + } + if d.Uint != tt.wantUint { + t.Errorf("Scan() Uint = %v, want %v", d.Uint, tt.wantUint) + } + }) + } +} + +func TestNullableDBUint_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + input []byte + wantUint uint + wantErr bool + }{ + { + name: "UnmarshalJSON should unmarshal integer value", + input: []byte("10"), + wantUint: uint(10), + wantErr: false, + }, + { + name: "UnmarshalJSON should return zero Uint when data is invalid", + input: []byte(`"invalid"`), + wantUint: uint(0), + wantErr: false, + }, + // Add more tests for other scenarios + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var d NullableDBUint + err := d.UnmarshalJSON(tt.input) + if err != nil && !tt.wantErr { + t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + if d.Uint != tt.wantUint { + t.Errorf("UnmarshalJSON() Uint = %v, want %v", d.Uint, tt.wantUint) + } + }) + } +} + +func TestNullableDBUint_MarshalJSON(t *testing.T) { + tests := []struct { + name string + input NullableDBUint + wantOutput []byte + wantErr bool + }{ + { + name: "MarshalJSON should marshal nil when Uint is 0", + input: NullableDBUint{Uint: 0}, + wantOutput: []byte("null"), + wantErr: false, + }, + { + name: "MarshalJSON should marshal Uint as JSON value", + input: NullableDBUint{Uint: 10}, + wantOutput: []byte("10"), + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotOutput, gotErr := tt.input.MarshalJSON() + if (gotErr != nil) != tt.wantErr { + t.Errorf("MarshalJSON() error = %v, wantErr %v", gotErr, tt.wantErr) + } + if string(gotOutput) != string(tt.wantOutput) { + t.Errorf("MarshalJSON() output = %s, want %s", gotOutput, tt.wantOutput) + } + }) + } +} diff --git a/backend/internal/types/jsonb_test.go b/backend/internal/types/jsonb_test.go new file mode 100644 index 0000000..c4702ca --- /dev/null +++ b/backend/internal/types/jsonb_test.go @@ -0,0 +1,133 @@ +package types + +import ( + "encoding/json" + "testing" +) + +// TestJSONBValue tests the Value method of the JSONB type +func TestJSONBValue(t *testing.T) { + j := JSONB{ + Decoded: map[string]interface{}{ + "name": "John", + "age": 30, + }, + } + + value, err := j.Value() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + // nolint: goconst + if value != `{"age":30,"name":"John"}` { + t.Errorf("Incorrect value. Expected: %s, Got: %s", `{"name":"John","age":30}`, value) + } +} + +// TestJSONBScan tests the Scan method of the JSONB type +func TestJSONBScan(t *testing.T) { + src := `{"name":"John","age":30}` + var j JSONB + + err := j.Scan(src) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedDecoded := map[string]interface{}{ + "name": "John", + "age": 30, + } + + if !jsonEqual(j.Decoded, expectedDecoded) { + t.Errorf("Incorrect decoded value. Expected: %v, Got: %v", expectedDecoded, j.Decoded) + } + + if j.Encoded != src { + t.Errorf("Incorrect encoded value. Expected: %s, Got: %s", src, j.Encoded) + } +} + +// TestJSONBUnmarshalJSON tests the UnmarshalJSON method of the JSONB type +func TestJSONBUnmarshalJSON(t *testing.T) { + data := []byte(`{"name":"John","age":30}`) + var j JSONB + + err := j.UnmarshalJSON(data) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedDecoded := map[string]interface{}{ + "name": "John", + "age": 30, + } + + if !jsonEqual(j.Decoded, expectedDecoded) { + t.Errorf("Incorrect decoded value. Expected: %v, Got: %v", expectedDecoded, j.Decoded) + } + + if j.Encoded != string(data) { + t.Errorf("Incorrect encoded value. Expected: %s, Got: %s", string(data), j.Encoded) + } +} + +// TestJSONBMarshalJSON tests the MarshalJSON method of the JSONB type +func TestJSONBMarshalJSON(t *testing.T) { + j := JSONB{ + Decoded: map[string]interface{}{ + "name": "John", + "age": 30, + }, + } + + result, err := j.MarshalJSON() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedResult := `{"age":30,"name":"John"}` + + if string(result) != expectedResult { + t.Errorf("Incorrect result. Expected: %s, Got: %s", expectedResult, string(result)) + } +} + +// TestJSONBAsStringArray tests the AsStringArray method of the JSONB type +func TestJSONBAsStringArray(t *testing.T) { + j := JSONB{ + Decoded: []string{"apple", "banana", "orange"}, + } + + strs, err := j.AsStringArray() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedStrs := []string{"apple", "banana", "orange"} + + if !stringSliceEqual(strs, expectedStrs) { + t.Errorf("Incorrect result. Expected: %v, Got: %v", expectedStrs, strs) + } +} + +// Helper function to compare JSON objects +func jsonEqual(a, b interface{}) bool { + aJSON, _ := json.Marshal(a) + bJSON, _ := json.Marshal(b) + return string(aJSON) == string(bJSON) +} + +// Helper function to compare string slices +func stringSliceEqual(a, b []string) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} diff --git a/backend/internal/types/nullable_db_date_test.go b/backend/internal/types/nullable_db_date_test.go new file mode 100644 index 0000000..5b853ae --- /dev/null +++ b/backend/internal/types/nullable_db_date_test.go @@ -0,0 +1,107 @@ +package types + +import ( + "testing" + "time" +) + +// TestNullableDBDateValue tests the Value method of the NullableDBDate type +func TestNullableDBDateValue(t *testing.T) { + tme := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + d := NullableDBDate{ + Time: &tme, + } + + value, err := d.Value() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedValue := tme.Unix() + + if value != expectedValue { + t.Errorf("Incorrect value. Expected: %d, Got: %v", expectedValue, value) + } +} + +// TestNullableDBDateScan tests the Scan method of the NullableDBDate type +func TestNullableDBDateScan(t *testing.T) { + var d NullableDBDate + + err := d.Scan(int64(1640995200)) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedTime := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + + if !expectedTime.Equal(*d.Time) { + t.Errorf("Incorrect time. Expected: %v, Got: %v", expectedTime, *d.Time) + } +} + +// TestNullableDBDateUnmarshalJSON tests the UnmarshalJSON method of the NullableDBDate type +func TestNullableDBDateUnmarshalJSON(t *testing.T) { + data := []byte(`1640995200`) + var d NullableDBDate + + err := d.UnmarshalJSON(data) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedTime := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + + if !expectedTime.Equal(*d.Time) { + t.Errorf("Incorrect time. Expected: %v, Got: %v", expectedTime, *d.Time) + } +} + +// TestNullableDBDateMarshalJSON tests the MarshalJSON method of the NullableDBDate type +func TestNullableDBDateMarshalJSON(t *testing.T) { + tme := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + d := NullableDBDate{ + Time: &tme, + } + + result, err := d.MarshalJSON() + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + expectedResult := []byte(`1640995200`) + + if string(result) != string(expectedResult) { + t.Errorf("Incorrect result. Expected: %s, Got: %s", expectedResult, result) + } +} + +// TestNullableDBDateAsInt64 tests the AsInt64 method of the NullableDBDate type +func TestNullableDBDateAsInt64(t *testing.T) { + tme := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + d := NullableDBDate{ + Time: &tme, + } + + unixtime := d.AsInt64() + expectedUnixtime := tme.Unix() + + if unixtime != expectedUnixtime { + t.Errorf("Incorrect unixtime. Expected: %d, Got: %d", expectedUnixtime, unixtime) + } +} + +// TestNullableDBDateAsString tests the AsString method of the NullableDBDate type +func TestNullableDBDateAsString(t *testing.T) { + tme := time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC) + d := NullableDBDate{ + Time: &tme, + } + + str := d.AsString() + expectedStr := tme.String() + + if str != expectedStr { + t.Errorf("Incorrect string. Expected: %s, Got: %s", expectedStr, str) + } +} diff --git a/backend/internal/util/interfaces_test.go b/backend/internal/util/interfaces_test.go new file mode 100644 index 0000000..99542d3 --- /dev/null +++ b/backend/internal/util/interfaces_test.go @@ -0,0 +1,33 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFindItemInInterface(t *testing.T) { + obj := map[string]interface{}{ + "key1": "value1", + "key2": 10, + "key3": map[string]interface{}{ + "nestedKey": "nestedValue", + }, + "key4": []interface{}{"item1", "item2"}, + } + + // Test case 1: Key exists at the top level + result, found := FindItemInInterface("key1", obj) + assert.Equal(t, true, found) + assert.Equal(t, "value1", result) + + // Test case 2: Key exists at a nested level + result, found = FindItemInInterface("nestedKey", obj) + assert.Equal(t, true, found) + assert.Equal(t, "nestedValue", result) + + // Test case 3: Key does not exist + result, found = FindItemInInterface("nonExistentKey", obj) + assert.Equal(t, false, found) + assert.Equal(t, nil, result) +} diff --git a/backend/internal/util/slices_test.go b/backend/internal/util/slices_test.go index f2f1871..17acd8a 100644 --- a/backend/internal/util/slices_test.go +++ b/backend/internal/util/slices_test.go @@ -1,6 +1,7 @@ package util import ( + "reflect" "testing" "github.com/stretchr/testify/assert" @@ -90,3 +91,21 @@ func TestConvertIntSliceToString(t *testing.T) { str := ConvertIntSliceToString(items) assert.Equal(t, expectedStr, str) } + +func TestConvertStringSliceToInterface(t *testing.T) { + testCases := []struct { + input []string + expected []interface{} + }{ + {[]string{"hello", "world"}, []interface{}{"hello", "world"}}, + {[]string{"apple", "banana", "cherry"}, []interface{}{"apple", "banana", "cherry"}}, + {[]string{}, []interface{}{}}, // Empty slice should return an empty slice + } + + for _, tc := range testCases { + result := ConvertStringSliceToInterface(tc.input) + if !reflect.DeepEqual(result, tc.expected) { + t.Errorf("Expected: %v, Got: %v", tc.expected, result) + } + } +} diff --git a/backend/internal/util/strings_test.go b/backend/internal/util/strings_test.go index d9bd24b..2f5af42 100644 --- a/backend/internal/util/strings_test.go +++ b/backend/internal/util/strings_test.go @@ -49,3 +49,19 @@ upstream npm_upstream_5 { }) } } + +func TestPrettyPrintJSON(t *testing.T) { + testCases := []struct { + input string + expected string + }{ + {`{"name":"John","age":30,"city":"New York"}`, "{\n \"name\": \"John\",\n \"age\": 30,\n \"city\": \"New York\"\n}"}, + {`{"fruit":"apple","color":"red"}`, "{\n \"fruit\": \"apple\",\n \"color\": \"red\"\n}"}, + {"invalid-json", "invalid-json"}, // non-JSON input should return the original string unchanged + } + + for _, tc := range testCases { + result := PrettyPrintJSON(tc.input) + assert.Equal(t, tc.expected, result) + } +} diff --git a/backend/internal/util/time_test.go b/backend/internal/util/time_test.go new file mode 100644 index 0000000..260d3fb --- /dev/null +++ b/backend/internal/util/time_test.go @@ -0,0 +1,25 @@ +package util + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestUnixMilliToNiceFormat(t *testing.T) { + tests := []struct { + input int64 + expected string + }{ + {0, "1970-01-01 10:00:00"}, // Unix epoch time + {1568000000000, "2019-09-09 13:33:20"}, // Arbitrary millisecond timestamp + {1636598400000, "2021-11-11 12:40:00"}, // Another arbitrary millisecond timestamp + {-1000000000000, "1938-04-25 08:13:20"}, // Negative millisecond timestamp + {9223372036854775807, "1970-01-01 09:59:59"}, // Maximum representable millisecond timestamp + } + + for _, test := range tests { + output := UnixMilliToNiceFormat(test.input) + assert.Equal(t, test.expected, output) + } +}