From a5bc1a3ed8c9028bfd4c485f28b144d005221756 Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 07:46:05 +0000 Subject: [PATCH] feat(forge): add safe client stringers Co-Authored-By: Virgil --- client.go | 13 +++++++++++++ client_test.go | 13 +++++++++++++ forge.go | 9 +++++++++ forge_test.go | 13 +++++++++++++ 4 files changed, 48 insertions(+) diff --git a/client.go b/client.go index fb5e288..86ace96 100644 --- a/client.go +++ b/client.go @@ -159,6 +159,19 @@ func (c *Client) HTTPClient() *http.Client { return c.httpClient } +// String returns a safe summary of the client configuration. +// +// Usage: +// +// s := client.String() +func (c *Client) String() string { + tokenState := "unset" + if c.HasToken() { + tokenState = "set" + } + return core.Concat("forge.Client{baseURL=", strconv.Quote(c.baseURL), ", token=", tokenState, ", userAgent=", strconv.Quote(c.userAgent), "}") +} + // HasToken reports whether the client was configured with an API token. // // Usage: diff --git a/client_test.go b/client_test.go index fbae590..79cd19a 100644 --- a/client_test.go +++ b/client_test.go @@ -2,6 +2,7 @@ package forge import ( "context" + "fmt" json "github.com/goccy/go-json" "net/http" "net/http/httptest" @@ -225,6 +226,18 @@ func TestClient_WithHTTPClient_Good(t *testing.T) { } } +func TestClient_String_Good(t *testing.T) { + c := NewClient("https://forge.lthn.ai", "tok", WithUserAgent("go-forge/1.0")) + got := fmt.Sprint(c) + want := `forge.Client{baseURL="https://forge.lthn.ai", token=set, userAgent="go-forge/1.0"}` + if got != want { + t.Fatalf("got %q, want %q", got, want) + } + if got := c.String(); got != want { + t.Fatalf("got String()=%q, want %q", got, want) + } +} + func TestAPIError_Error_Good(t *testing.T) { e := &APIError{StatusCode: 404, Message: "not found", URL: "/api/v1/repos/x/y"} got := e.Error() diff --git a/forge.go b/forge.go index c3a3e34..5d0ce5c 100644 --- a/forge.go +++ b/forge.go @@ -110,3 +110,12 @@ func (f *Forge) HTTPClient() *http.Client { return f.client.HTTPClient() } // _ = "authenticated" // } func (f *Forge) HasToken() bool { return f.client.HasToken() } + +// String returns a safe summary of the Forge client. +// +// Usage: +// +// s := f.String() +func (f *Forge) String() string { + return "forge.Forge{" + f.client.String() + "}" +} diff --git a/forge_test.go b/forge_test.go index 89968c7..701a36b 100644 --- a/forge_test.go +++ b/forge_test.go @@ -3,6 +3,7 @@ package forge import ( "bytes" "context" + "fmt" json "github.com/goccy/go-json" "net/http" "net/http/httptest" @@ -81,6 +82,18 @@ func TestForge_HasToken_Bad(t *testing.T) { } } +func TestForge_String_Good(t *testing.T) { + f := NewForge("https://forge.lthn.ai", "tok", WithUserAgent("go-forge/1.0")) + got := fmt.Sprint(f) + want := `forge.Forge{forge.Client{baseURL="https://forge.lthn.ai", token=set, userAgent="go-forge/1.0"}}` + if got != want { + t.Fatalf("got %q, want %q", got, want) + } + if got := f.String(); got != want { + t.Fatalf("got String()=%q, want %q", got, want) + } +} + func TestRepoService_ListOrgRepos_Good(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet {