test(08-07): add failing repeatable-flag RED anchor for bonfire

- TestPhase8RedBonfireFlags asserts Input.Flags preserves ordered
  repeated --redirect-uri/--scope values while existing scalar --mode
  flags via Input.Flag stay unaffected
- Adds the compiling seam (Flag.Repeatable, Input.Flags,
  cobraInput.Flags) without wiring Cobra StringSlice registration yet,
  so the test fails with PHASE8_RED:bonfire-flags (D-19)
This commit is contained in:
Jakub Zych
2026-09-23 21:54:44 +02:00
parent d70e412138
commit 7096a90235
2 changed files with 81 additions and 0 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"errors"
"slices"
"strings"
"testing"
)
@@ -244,6 +245,61 @@ func TestNonTTYProgressSkipsIntraDecile(t *testing.T) {
}
}
// TestPhase8RedBonfireFlags is the Phase 8 Wave 7 RED anchor (08-07-PLAN.md
// Task 1, D-19). bonfire.Flag/Input are scalar-only today
// (08-PATTERNS.md "bonfire repeatable-flag gap"): a Repeatable flag
// registered through Command.Flags must preserve every repeated
// `--name=value` occurrence in order via Input.Flags, while an ordinary
// scalar flag declared alongside it keeps working through Input.Flag
// unmodified. It fails with the PHASE8_RED:bonfire-flags sentinel while
// Repeatable is not yet wired into Cobra registration;
// scripts/check-phase8-red.sh verifies this failure is fail-closed.
func TestPhase8RedBonfireFlags(t *testing.T) {
var buf bytes.Buffer
var gotRedirect, gotScope []string
var gotMode string
var gotModeOK bool
root, err := NewRootIO("app", []Command{{
Name: "demo:repeat",
Description: "Demo repeatable flags",
Flags: []Flag{
{Name: "redirect-uri", Repeatable: true, Description: "repeatable redirect URI"},
{Name: "scope", Repeatable: true, Description: "repeatable scope"},
{Name: "mode", Default: "slow", Description: "scalar, unaffected by D-19"},
},
Run: func(ctx context.Context, in Input, out Output) error {
gotRedirect = in.Flags("redirect-uri")
gotScope = in.Flags("scope")
gotMode, gotModeOK = in.Flag("mode")
return nil
},
}}, strings.NewReader(""), &buf, &buf)
if err != nil {
t.Fatal(err)
}
root.SetArgs([]string{
"demo:repeat",
"--redirect-uri=https://a.example/callback",
"--redirect-uri=https://b.example/callback",
"--scope=read",
"--mode=fast",
})
if err := root.Execute(); err != nil {
t.Fatal(err)
}
wantRedirect := []string{"https://a.example/callback", "https://b.example/callback"}
if !slices.Equal(gotRedirect, wantRedirect) {
t.Fatalf("PHASE8_RED:bonfire-flags: repeated --redirect-uri via Input.Flags = %v, want %v in insertion order", gotRedirect, wantRedirect)
}
if !slices.Equal(gotScope, []string{"read"}) {
t.Fatalf("PHASE8_RED:bonfire-flags: repeated --scope via Input.Flags = %v, want [read]", gotScope)
}
if !gotModeOK || gotMode != "fast" {
t.Fatalf("PHASE8_RED:bonfire-flags: existing scalar --mode via Input.Flag = (%q, %v), want (\"fast\", true) unaffected by Repeatable", gotMode, gotModeOK)
}
}
func TestHelpUsesSharedAdapter(t *testing.T) {
var buf bytes.Buffer
root, err := NewRoot("hello", []Command{{