test(trail): cover url wire-compat (old/new cli × old/new api) · Entire

test(trail): cover url wire-compat (old/new cli × old/new api)

4bef6a1→main·

toothbrush·3w ago·1 file·+42 added/-1 removed

Decode test proves a new server payload carrying url decodes into the new TrailResource (new cli + new api) and is ignored by a struct without the field (old cli + new api). new cli + old api is covered by trailDisplayURL's fallback test.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

6d7d67ae97b1View transcript

[?
Add Web URLs to Trail CommandsClaude Code·Opus 4.8[1m]·1 step](/content/gh/entireio/cli/session/18a97739-bf62-4c0b-9cf2-9a1673f59583#timeline-6d7d67ae97b1/index.html)

Changes

1

1
2
3
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

package api

import "testing"
import (
    "encoding/json"
    "testing"
)

// TestTrailResourceDecodesServerURL covers the wire-compatibility matrix for the
// `url` field the API added:
//   - new cli + new api: the field decodes into TrailResource.URL and is used.
//   - old cli + new api: a client struct predating the field ignores the extra
//     key without error (Go's json.Unmarshal drops unknown fields), so an older
//     CLI keeps working against a newer server.
//
// (new cli + old api is exercised by trailDisplayURL's fallback in the cli pkg.)
func TestTrailResourceDecodesServerURL(t *testing.T) {
    t.Parallel()

// Shape a newer server would emit: includes `url`.
    payload := []byte(`{"id":"t1","number":640,"url":"https://entire.io/gh/o/r/trails/640/slug","branch":"feat/x","title":"T"}`)

// new cli + new api: URL is captured and available to display.
    var newClient TrailResource
    if err := json.Unmarshal(payload, &newClient); err != nil {
        t.Fatalf("new client failed to decode new payload: %v", err)
    }
    if newClient.URL != "https://entire.io/gh/o/r/trails/640/slug" {
        t.Fatalf("URL = %q, want server-provided url", newClient.URL)
    }

// old cli + new api: a struct without a URL field must not choke on the
    // extra key, and still decodes the fields it knows about.
    var oldClient struct {
        ID     string `json:"id"`
        Number int    `json:"number"`
        Title  string `json:"title"`
    }
    if err := json.Unmarshal(payload, &oldClient); err != nil {
        t.Fatalf("old client rejected new payload with extra url field: %v", err)
    }
    if oldClient.Number != 640 || oldClient.Title != "T" {
        t.Fatalf("old client decoded wrong values: %+v", oldClient)
    }
}

func TestTrailResourceToMetadataUsesID(t *testing.T) {
    t.Parallel()

Mcmd/entire/cli/api/trail_types_test.go+42/-1