Enhance MySubaru API integration with improved error handling and new utility functions
All checks were successful
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Successful in 25s
All checks were successful
Golan Testing / testing (1.24.x, ubuntu-latest) (push) Successful in 25s
- Refactor Response struct's parse method to return detailed error messages based on API error codes. - Introduce UnixTime type for handling Unix timestamps in JSON marshaling and unmarshaling. - Add email masking utility function to obfuscate email addresses for privacy. - Implement containsValueInStruct function to check for substring presence in struct fields. - Create comprehensive unit tests for UnixTime, email masking, and struct value checking. - Update vehicle service request method documentation for clarity.
This commit is contained in:
204
mysubaru_test.go
Normal file
204
mysubaru_test.go
Normal file
@ -0,0 +1,204 @@
|
||||
package mysubaru
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestUnixTime_UnmarshalJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantTime time.Time
|
||||
wantError bool
|
||||
}{
|
||||
{
|
||||
name: "valid unix timestamp",
|
||||
input: "1700000000",
|
||||
wantTime: time.Unix(1700000000, 0),
|
||||
},
|
||||
{
|
||||
name: "invalid string",
|
||||
input: "\"notanumber\"",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "empty input",
|
||||
input: "",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "float value",
|
||||
input: "1700000000.123",
|
||||
wantError: true,
|
||||
},
|
||||
{
|
||||
name: "zero timestamp",
|
||||
input: "0",
|
||||
wantTime: time.Unix(0, 0),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var ut UnixTime
|
||||
err := ut.UnmarshalJSON([]byte(tt.input))
|
||||
if (err != nil) != tt.wantError {
|
||||
t.Errorf("UnmarshalJSON() error = %v, wantError %v", err, tt.wantError)
|
||||
return
|
||||
}
|
||||
if !tt.wantError && !ut.Time.Equal(tt.wantTime) {
|
||||
t.Errorf("UnmarshalJSON() got = %v, want %v", ut.Time, tt.wantTime)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_UnmarshalJSON_withJSONUnmarshal(t *testing.T) {
|
||||
type testStruct struct {
|
||||
Time UnixTime `json:"time"`
|
||||
}
|
||||
input := `{"time":1700000000}`
|
||||
var ts testStruct
|
||||
err := json.Unmarshal([]byte(input), &ts)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Unmarshal failed: %v", err)
|
||||
}
|
||||
want := time.Unix(1700000000, 0)
|
||||
if !ts.Time.Time.Equal(want) {
|
||||
t.Errorf("UnmarshalJSON() got = %v, want %v", ts.Time.Time, want)
|
||||
}
|
||||
}
|
||||
func TestUnixTime_MarshalJSON(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input time.Time
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "epoch",
|
||||
input: time.Unix(0, 0),
|
||||
want: "0",
|
||||
},
|
||||
{
|
||||
name: "positive unix time",
|
||||
input: time.Unix(1700000000, 0),
|
||||
want: "1700000000",
|
||||
},
|
||||
{
|
||||
name: "negative unix time",
|
||||
input: time.Unix(-100, 0),
|
||||
want: "-100",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ut := UnixTime{Time: tt.input}
|
||||
got, err := ut.MarshalJSON()
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalJSON() error = %v", err)
|
||||
}
|
||||
if string(got) != tt.want {
|
||||
t.Errorf("MarshalJSON() = %s, want %s", string(got), tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnixTime_MarshalJSON_withJSONMarshal(t *testing.T) {
|
||||
type testStruct struct {
|
||||
Time UnixTime `json:"time"`
|
||||
}
|
||||
ts := testStruct{Time: UnixTime{Time: time.Unix(1700000000, 0)}}
|
||||
b, err := json.Marshal(ts)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal failed: %v", err)
|
||||
}
|
||||
want := `{"time":1700000000}`
|
||||
if string(b) != want {
|
||||
t.Errorf("json.Marshal() = %s, want %s", string(b), want)
|
||||
}
|
||||
}
|
||||
|
||||
// func TestResponse_parse(t *testing.T) {
|
||||
// tests := []struct {
|
||||
// name string
|
||||
// input string
|
||||
// wantErr error
|
||||
// wantCode string
|
||||
// wantLog string
|
||||
// }{
|
||||
// {
|
||||
// name: "success response",
|
||||
// input: `{"success":true,"dataName":"foo","data":{}}`,
|
||||
// wantErr: nil,
|
||||
// },
|
||||
// {
|
||||
// name: "invalid json",
|
||||
// input: `{"success":tru`,
|
||||
// wantErr: errors.New("error while parsing json:"),
|
||||
// wantLog: "error while parsing json",
|
||||
// },
|
||||
// {
|
||||
// name: "API_ERROR_NO_ACCOUNT",
|
||||
// input: `{"success":false,"errorCode":"noAccount","dataName":"errorResponse","data":{}}`,
|
||||
// wantErr: errors.New("error in response: Account not found"),
|
||||
// wantCode: "noAccount",
|
||||
// wantLog: "error in response",
|
||||
// },
|
||||
// {
|
||||
// name: "API_ERROR_INVALID_CREDENTIALS",
|
||||
// input: `{"success":false,"errorCode":"invalidCredentials","dataName":"errorResponse","data":{}}`,
|
||||
// wantErr: errors.New("error in response: Invalid Credentials"),
|
||||
// wantCode: "invalidCredentials",
|
||||
// wantLog: "error in response",
|
||||
// },
|
||||
// {
|
||||
// name: "API_ERROR_SOA_403",
|
||||
// input: `{"success":false,"errorCode":"404-soa-unableToParseResponseBody","dataName":"errorResponse","data":{}}`,
|
||||
// wantErr: errors.New("error in response: Unable to parse response body, SOA 403 error"),
|
||||
// wantCode: "404-soa-unableToParseResponseBody",
|
||||
// wantLog: "error in response",
|
||||
// },
|
||||
// {
|
||||
// name: "unknown error code",
|
||||
// input: `{"success":false,"errorCode":"somethingElse","dataName":"errorResponse","data":{}}`,
|
||||
// wantErr: errors.New("error in response: somethingElse"),
|
||||
// wantCode: "somethingElse",
|
||||
// wantLog: "error in response",
|
||||
// },
|
||||
// {
|
||||
// name: "no errorCode but not success",
|
||||
// input: `{"success":false,"dataName":"errorResponse","data":{}}`,
|
||||
// wantErr: nil,
|
||||
// },
|
||||
// }
|
||||
|
||||
// for _, tt := range tests {
|
||||
// t.Run(tt.name, func(t *testing.T) {
|
||||
// var resp Response
|
||||
// logger := slog.New(slog.NewTextHandler(nil, nil))
|
||||
// got, err := resp.parse([]byte(tt.input), logger)
|
||||
// if tt.wantErr != nil {
|
||||
// if err == nil {
|
||||
// t.Fatalf("expected error, got nil")
|
||||
// }
|
||||
// if !contains(err.Error(), tt.wantErr.Error()) {
|
||||
// t.Errorf("parse() error = %v, want %v", err, tt.wantErr)
|
||||
// }
|
||||
// } else if err != nil {
|
||||
// t.Errorf("parse() unexpected error: %v", err)
|
||||
// }
|
||||
// if tt.wantCode != "" && got != nil && got.ErrorCode != tt.wantCode {
|
||||
// t.Errorf("parse() got.ErrorCode = %v, want %v", got.ErrorCode, tt.wantCode)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
|
||||
// // contains is a helper for substring matching.
|
||||
// func contains(s, substr string) bool {
|
||||
// return bytes.Contains([]byte(s), []byte(substr))
|
||||
// }
|
Reference in New Issue
Block a user