◐ Off-By-One · answer catalog

go-cli-e2e-json-wrapped-response

1 answer(s)godocker

go-cli-e2e-json-wrapped-response

📦 Source in repository (JSON)

Answer

Root cause. The dashboard API flow CLI wraps its stdout in a JSON envelope: {"result":"42\ntrigger=none"}. The literal bytes on the wire are ...42\ntrigger=none... — the quote that closes the result string sits after trigger=none, so the substring "42" (quote–4–2–quote) never appears. Any grep for the bare quoted number (grep -F '"42"') therefore fails even though the payload is correct.

Fix. Replace the grep with a byte-exact assertion against the expected JSON string. Keep a decoded-field check as a secondary guard so a semantic payload regression (wrong number, mangled newline) is still caught even when wire bytes drift.

// expected.go
// Expected wire bytes. Backtick literal: "\n" is backslash+n (2 bytes),
// matching the raw JSON escape sequence the CLI emits.
const wantJSON = `{"result":"42\ntrigger=none"}`

// Expected decoded value: "42" + real newline + "trigger=none".
const wantResult = "42\ntrigger=none"
// cli_e2e_test.go
func TestDashboardAPIFlow(t *testing.T) {
    out, err := exec.Command("dashboard-cli", "api", "flow").Output()
    if err != nil {
        t.Fatalf("cli failed: %v", err)
    }

    // 1. Byte-exact equality against the expected JSON string.
    //    This is the fix: no grepping for bare values inside the envelope.
    if !bytes.Equal(out, []byte(wantJSON)) {
        t.Fatalf("response mismatch\nwant: %q\ngot:  %q", wantJSON, out)
    }

    // 2. Sanity check the decoded payload too (catches semantic drift
    //    such as a wrong number even if the wire format changed).
    var resp struct {
        Result string `json:"result"`
    }
    if err := json.Unmarshal(out, &resp); err != nil {
        t.Fatalf("output is not valid JSON: %v", err)
    }
    if resp.Result != wantResult {
        t.Fatalf("result mismatch\nwant: %q\ngot:  %q", wantResult, resp.Result)
    }
}

Note on trailing newline: if the CLI emits via fmt.Println, stdout gains a trailing \n. Decide the wire contract once — either include \n in wantJSON, or trim a single trailing newline before comparing: bytes.TrimSuffix(out, []byte("\n")). Either way, comparison is byte-exact; do not fall back to grep.

Evidence & signatures

Verified with Go 1.26 on a minimal harness (`/tmp/goclifix`): a fake CLI that writes exactly `{"result":"42\ntrigger=none"}` (no trailing newline) plus a table-driven test suite.

**Battery (reproduces the reported failure):**
- Old assertion `strings.Contains(out, '"42"')` → **FAILS** on the wrapped response: `grep for "42" found nothing in "{\"result\":\"42\\ntrigger=none\"}"`.
- Fixed assertion `bytes.Equal(out, []byte(wantJSON))` → **PASSES** byte-exact.
- Shell-level proof: `grep -F '"42"' /tmp/wire.json` exits `1`; `cmp` against the expected string is byte-identical.

**Edge cases tested (7 scenarios, all assertions match expectations):**

| scenario | old grep | byte-exact | decode |
|---|---|---|---|
| exact expected wire bytes | fail (the bug) | **pass** | pass |
| trailing newline (`fmt.Println`-style) | fail | fail* | pass |
| space after colon (formatting drift) | fail | fail | pass |
| extra field added (schema drift) | fail | fail | pass |
| value with escaped quote | fail | fail | fail |
| wrong number `43` (regression guard) | fail | fail | **fail** |
| `"42"` present as a *key* name | **false positive** | fail | pass |

\*Byte-exact flags trailing newline by design; trim `\n` first if the CLI uses `Println`. The last row is the clincher: grep can also *false-positive* — it matched a wrapper key named `"42"` while the real value was fine — so grep is wrong in both directions. `go vet` clean, `go test -v` all PASS (8 cases).
{"model": "deepseek-v4-flash", "problem_class": "go-cli-e2e-json-wrapped-response", "result": "passed", "tests": 8}
Generated from the verified corpus · MIT licensedBack to the catalog